Skip to content

Commit 0c4c626

Browse files
committed
Add more analyzers
1 parent 168e97d commit 0c4c626

23 files changed

+494
-41
lines changed

build.cake

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
#tool nuget:?package=MSBuild.SonarQube.Runner.Tool
2-
#addin nuget:?package=Cake.Sonar
1+
#tool "nuget:?package=MSBuild.SonarQube.Runner.Tool&version=4.3.1"
2+
3+
#addin "nuget:?package=Cake.Sonar&version=1.1.18"
34

45
var target = Argument("target", "Default");
56
var buildConfiguration = Argument("buildConfig", "Debug");
@@ -11,53 +12,53 @@ var projectName = solutionName;
1112

1213
var solutionFile = string.Format("./src/{0}.sln", solutionName);
1314
var solutionFolder = string.Format("./src/{0}/", solutionName);
15+
var testBinaries = string.Format("test/src/**/ReSharper.Structured.Logging.Tests.dll", solutionFolder);
1416
var projectFile = string.Format("{0}{1}.csproj", solutionFolder, projectName);
1517

1618
Task("AppendBuildNumber")
1719
.WithCriteria(BuildSystem.AppVeyor.IsRunningOnAppVeyor)
1820
.Does(() =>
1921
{
20-
var buildNumber = BuildSystem.AppVeyor.Environment.Build.Number;
21-
extensionsVersion = string.Format("{0}.{1}", extensionsVersion, buildNumber);
22+
var buildNumber = BuildSystem.AppVeyor.Environment.Build.Number;
23+
extensionsVersion = string.Format("{0}.{1}", extensionsVersion, buildNumber);
2224
});
2325

2426
Task("UpdateBuildVersion")
2527
.IsDependentOn("AppendBuildNumber")
2628
.WithCriteria(BuildSystem.AppVeyor.IsRunningOnAppVeyor)
2729
.Does(() =>
2830
{
29-
BuildSystem.AppVeyor.UpdateBuildVersion(extensionsVersion);
31+
BuildSystem.AppVeyor.UpdateBuildVersion(extensionsVersion);
3032
});
3133

3234
Task("NugetRestore")
3335
.Does(() =>
3436
{
35-
NuGetRestore(solutionFile);
37+
NuGetRestore(solutionFile);
3638
});
3739

3840
Task("Build")
3941
.IsDependentOn("NugetRestore")
4042
.Does(() =>
4143
{
4244
MSBuild(solutionFile, new MSBuildSettings {
43-
Configuration = buildConfiguration
45+
Configuration = buildConfiguration
4446
});
4547
});
4648

47-
4849
Task("NugetPack")
4950
.IsDependentOn("AppendBuildNumber")
5051
.IsDependentOn("Build")
5152
.Does(() =>
5253
{
53-
var buildPath = string.Format("./src/{0}/bin/{1}", solutionName, buildConfiguration);
54+
var buildPath = string.Format("./src/{0}/bin/{1}", solutionName, buildConfiguration);
5455

55-
var files = new List<NuSpecContent>();
56+
var files = new List<NuSpecContent>();
5657
files.Add(new NuSpecContent {Source = string.Format("{0}/{1}.dll", buildPath, projectName), Target = "dotFiles"});
5758

5859
if (buildConfiguration == "Debug")
5960
{
60-
files.Add(new NuSpecContent {Source = string.Format("{0}/{1}.pdb", buildPath, projectName), Target = "dotFiles"});
61+
files.Add(new NuSpecContent {Source = string.Format("{0}/{1}.pdb", buildPath, projectName), Target = "dotFiles"});
6162
}
6263

6364
var nuGetPackSettings = new NuGetPackSettings {
@@ -75,8 +76,8 @@ Task("NugetPack")
7576
NoPackageAnalysis = true,
7677
Files = files,
7778
OutputDirectory = ".",
78-
Dependencies = new [] { new NuSpecDependency() { Id = "Wave", Version = waveVersion } },
79-
ReleaseNotes = new [] { "https://github.com/olsh/resharper-structured-logging/releases" }
79+
Dependencies = new [] { new NuSpecDependency() { Id = "Wave", Version = waveVersion } },
80+
ReleaseNotes = new [] { "https://github.com/olsh/resharper-structured-logging/releases" }
8081
};
8182

8283
NuGetPack(nuGetPackSettings);
@@ -113,15 +114,15 @@ Task("CreateArtifact")
113114
.WithCriteria(BuildSystem.AppVeyor.IsRunningOnAppVeyor)
114115
.Does(() =>
115116
{
116-
var artifactFile = string.Format("{0}.{1}.nupkg", projectName, extensionsVersion);
117-
BuildSystem.AppVeyor.UploadArtifact(artifactFile);
117+
var artifactFile = string.Format("{0}.{1}.nupkg", projectName, extensionsVersion);
118+
BuildSystem.AppVeyor.UploadArtifact(artifactFile);
118119
});
119120

120121
Task("CI")
121122
.IsDependentOn("Sonar")
122123
.IsDependentOn("CreateArtifact");
123124

124125
Task("Default")
125-
.IsDependentOn("NugetPack");
126+
.IsDependentOn("NugetPack");
126127

127128
RunTarget(target);
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
using System.Linq;
2+
3+
using JetBrains.ReSharper.Feature.Services.Daemon;
4+
using JetBrains.ReSharper.Psi;
5+
using JetBrains.ReSharper.Psi.CSharp.Tree;
6+
using JetBrains.ReSharper.Psi.Util;
7+
8+
using ReSharper.Structured.Logging.Extensions;
9+
using ReSharper.Structured.Logging.Highlighting;
10+
11+
namespace ReSharper.Structured.Logging.Analyzer
12+
{
13+
[ElementProblemAnalyzer(typeof(IInvocationExpression))]
14+
public class CorrectExceptionPassingAnalyzer : ElementProblemAnalyzer<IInvocationExpression>
15+
{
16+
protected override void Run(
17+
IInvocationExpression element,
18+
ElementProblemAnalyzerData data,
19+
IHighlightingConsumer consumer)
20+
{
21+
var templateArgument = element.GetTemplateArgument();
22+
if (templateArgument == null)
23+
{
24+
return;
25+
}
26+
27+
var stringLiteral = StringLiteralAltererUtil.TryCreateStringLiteralByExpression(templateArgument.Value);
28+
if (stringLiteral == null)
29+
{
30+
return;
31+
}
32+
33+
var templateArgumentIndex = templateArgument.IndexOf();
34+
var exceptionType = element.PsiModule.GetPredefinedType().TryGetType(PredefinedType.EXCEPTION_FQN);
35+
if (exceptionType == null)
36+
{
37+
return;
38+
}
39+
40+
ICSharpArgument invalidExceptionArgument = null;
41+
foreach (var argument in element.ArgumentList.Arguments)
42+
{
43+
var argumentType = argument.Value?.Type();
44+
if (!(argumentType is IDeclaredType declaredType))
45+
{
46+
continue;
47+
}
48+
49+
if (!declaredType.IsSubtypeOf(exceptionType))
50+
{
51+
continue;
52+
}
53+
54+
if (templateArgumentIndex > argument.IndexOf())
55+
{
56+
return;
57+
}
58+
59+
invalidExceptionArgument = argument;
60+
break;
61+
}
62+
63+
if (invalidExceptionArgument == null)
64+
{
65+
return;
66+
}
67+
68+
var overloadAvailable = false;
69+
var candidates = element.InvocationExpressionReference.GetCandidates().ToArray();
70+
var invalidArgumentIndex = invalidExceptionArgument.IndexOf();
71+
foreach (var candidate in candidates)
72+
{
73+
if (!(candidate.GetDeclaredElement() is IMethod declaredElement))
74+
{
75+
continue;
76+
}
77+
78+
foreach (var parameter in declaredElement.Parameters)
79+
{
80+
if (invalidArgumentIndex <= parameter.IndexOf())
81+
{
82+
break;
83+
}
84+
85+
if (parameter.Type.IsSubtypeOf(exceptionType))
86+
{
87+
overloadAvailable = true;
88+
break;
89+
}
90+
}
91+
92+
if (overloadAvailable)
93+
{
94+
break;
95+
}
96+
}
97+
98+
if (!overloadAvailable)
99+
{
100+
return;
101+
}
102+
103+
consumer.AddHighlighting(new ExceptionPassedAsTemplateArgumentWarning(invalidExceptionArgument.GetDocumentRange()));
104+
}
105+
}
106+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using System.Linq;
2+
3+
using JetBrains.ReSharper.Feature.Services.Daemon;
4+
using JetBrains.ReSharper.Psi.CSharp.Tree;
5+
using JetBrains.ReSharper.Psi.Tree;
6+
using JetBrains.ReSharper.Psi.Util;
7+
8+
using ReSharper.Structured.Logging.Extensions;
9+
using ReSharper.Structured.Logging.Highlighting;
10+
using ReSharper.Structured.Logging.Serilog.Parsing;
11+
12+
namespace ReSharper.Structured.Logging.Analyzer
13+
{
14+
[ElementProblemAnalyzer(typeof(IInvocationExpression))]
15+
public class DuplicatePropertiesTemplateAnalyzer : ElementProblemAnalyzer<IInvocationExpression>
16+
{
17+
private readonly MessageTemplateParser _messageTemplateParser;
18+
19+
public DuplicatePropertiesTemplateAnalyzer(MessageTemplateParser messageTemplateParser)
20+
{
21+
_messageTemplateParser = messageTemplateParser;
22+
}
23+
24+
protected override void Run(
25+
IInvocationExpression element,
26+
ElementProblemAnalyzerData data,
27+
IHighlightingConsumer consumer)
28+
{
29+
var templateArgument = element.GetTemplateArgument();
30+
if (templateArgument == null)
31+
{
32+
return;
33+
}
34+
35+
var stringLiteral = StringLiteralAltererUtil.TryCreateStringLiteralByExpression(templateArgument.Value);
36+
if (stringLiteral == null)
37+
{
38+
return;
39+
}
40+
41+
var messageTemplate = _messageTemplateParser.Parse(stringLiteral.CompiledValue);
42+
if (messageTemplate.NamedProperties == null)
43+
{
44+
return;
45+
}
46+
47+
foreach (var duplicates in messageTemplate.NamedProperties
48+
.GroupBy(n => n.PropertyName)
49+
.Where(g => g.Count() > 1))
50+
{
51+
foreach (var token in duplicates)
52+
{
53+
consumer.AddHighlighting(
54+
new DuplicateTemplatePropertyWarning(
55+
stringLiteral.Expression.GetDocumentRange()
56+
.GetTokenDocumentRange(token)));
57+
}
58+
}
59+
}
60+
}
61+
}

src/ReSharper.Structured.Logging/Analyzer/TemplateFormatAnalyzer.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ private static void HighlightUnusedArguments(
133133
consumer.AddHighlighting(new TemplateFormatStringArgumentIsNotUsedWarning(argument.Expression));
134134
}
135135
}
136+
else
137+
{
138+
consumer.AddHighlighting(new TemplateFormatStringArgumentIsNotUsedWarning(argument.Expression));
139+
}
136140
}
137141
}
138142
}

src/ReSharper.Structured.Logging/Extensions/PsiExtensions.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using JetBrains.ReSharper.Feature.Services.CSharp.CodeStyle.Suggestions;
66
using JetBrains.ReSharper.Psi;
77
using JetBrains.ReSharper.Psi.CSharp.Tree;
8+
using JetBrains.ReSharper.Psi.Util;
89
using JetBrains.Util;
910

1011
using ReSharper.Structured.Logging.Serilog.Parsing;
@@ -32,6 +33,18 @@ public static ICSharpArgument GetTemplateArgument(this IInvocationExpression inv
3233
a => a.GetMatchingParameterName() == templateParameterName);
3334
}
3435

36+
[CanBeNull]
37+
public static IStringLiteralAlterer GetMessageTemplateStringLiteral(this IInvocationExpression invocation)
38+
{
39+
var templateArgument = invocation.GetTemplateArgument();
40+
if (templateArgument == null)
41+
{
42+
return null;
43+
}
44+
45+
return StringLiteralAltererUtil.TryCreateStringLiteralByExpression(templateArgument.Value);
46+
}
47+
3548
public static DocumentRange GetTokenDocumentRange(this DocumentRange documentRange, MessageTemplateToken token)
3649
{
3750
var startOffset = documentRange.TextRange.StartOffset + token.StartIndex + 1;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using JetBrains.DocumentModel;
2+
using JetBrains.ReSharper.Feature.Services.Daemon;
3+
using JetBrains.ReSharper.Psi.CSharp;
4+
5+
using ReSharper.Structured.Logging.Highlighting;
6+
7+
[assembly:
8+
RegisterConfigurableSeverity(DuplicateTemplatePropertyWarning.SeverityId, null, HighlightingGroupIds.CompilerWarnings,
9+
DuplicateTemplatePropertyWarning.Message, DuplicateTemplatePropertyWarning.Message,
10+
Severity.WARNING)]
11+
12+
namespace ReSharper.Structured.Logging.Highlighting
13+
{
14+
[ConfigurableSeverityHighlighting(
15+
SeverityId,
16+
CSharpLanguage.Name,
17+
OverlapResolve = OverlapResolveKind.WARNING,
18+
ToolTipFormatString = Message)]
19+
public class DuplicateTemplatePropertyWarning : IHighlighting
20+
{
21+
public const string Message = "Duplicate properties in message template";
22+
23+
public const string SeverityId = "TemplateDuplicatePropertyProblem";
24+
25+
private readonly DocumentRange _documentRange;
26+
27+
public DuplicateTemplatePropertyWarning(DocumentRange documentRange)
28+
{
29+
_documentRange = documentRange;
30+
}
31+
32+
public string ErrorStripeToolTip => ToolTip;
33+
34+
public string ToolTip => Message;
35+
36+
public DocumentRange CalculateRange()
37+
{
38+
return _documentRange;
39+
}
40+
41+
public bool IsValid()
42+
{
43+
return _documentRange.IsValid();
44+
}
45+
}
46+
}

0 commit comments

Comments
 (0)