Skip to content

Commit

Permalink
Improve TokenType analyzer`s location mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
csaba-sagi-sonarsource authored and antonioaversa committed Sep 18, 2023
1 parent 700bc6f commit 8fd808c
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 27 deletions.
3 changes: 2 additions & 1 deletion analyzers/src/SonarAnalyzer.CFG/ShimLayer/SyntaxKindEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public static class SyntaxKindEx
public const SyntaxKind Utf8StringLiteralToken = (SyntaxKind)8520;
public const SyntaxKind Utf8SingleLineRawStringLiteralToken = (SyntaxKind)8521;
public const SyntaxKind Utf8MultiLineRawStringLiteralToken = (SyntaxKind)8522;
public const SyntaxKind PragmaChecksumDirectiveTrivia = (SyntaxKind)8560;
public const SyntaxKind ConflictMarkerTrivia = (SyntaxKind)8564;
public const SyntaxKind IsPatternExpression = (SyntaxKind)8657;
public const SyntaxKind RangeExpression = (SyntaxKind)8658;
Expand Down Expand Up @@ -84,9 +85,9 @@ public static class SyntaxKindEx
public const SyntaxKind FunctionPointerUnmanagedCallingConventionList = (SyntaxKind)9066;
public const SyntaxKind FunctionPointerUnmanagedCallingConvention = (SyntaxKind)9067;
public const SyntaxKind RecordStructDeclaration = (SyntaxKind)9068;
public const SyntaxKind LineSpanDirectiveTrivia = (SyntaxKind)9071;
public const SyntaxKind InterpolatedSingleLineRawStringStartToken = (SyntaxKind)9072;
public const SyntaxKind InterpolatedMultiLineRawStringStartToken = (SyntaxKind)9073;
public const SyntaxKind InterpolatedRawStringEndToken = (SyntaxKind)9074;
public const SyntaxKind PragmaChecksumDirectiveTrivia = (SyntaxKind)8560;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,88 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using Microsoft.CodeAnalysis.CSharp;

namespace SonarAnalyzer.Extensions;

public static class LocationExtensions
{
public static FileLinePositionSpan GetMappedLineSpanIfAvailable(this Location location) =>
GeneratedCodeRecognizer.IsRazorGeneratedFile(location.SourceTree)
? location.GetMappedLineSpan()
: location.GetLineSpan();
GeneratedCodeRecognizer.IsRazorGeneratedFile(location.SourceTree) ? location.GetMappedLineSpan() : location.GetLineSpan();

public static FileLinePositionSpan GetMappedLineSpanIfAvailable(this Location location, SyntaxToken token)
{
var node = token.Parent;
if (GeneratedCodeRecognizer.IsRazorGeneratedFile(location.SourceTree))
{
var mappedLocation = location.GetMappedLineSpan();
if (mappedLocation.HasMappedPath)
{
var lineDirective = FindLineDirecitive(node);
if (LineSpanDirectiveTriviaSyntaxWrapper.IsInstance(lineDirective)
&& (LineSpanDirectiveTriviaSyntaxWrapper)lineDirective is var lineSpanDirective
&& lineSpanDirective.CharacterOffset.ValueText is var stringValue
&& int.TryParse(stringValue, out var numericValue)
&& numericValue >= location.GetLineSpan().Span.End.Character)
{
return location.GetLineSpan();
}
}
return mappedLocation;
}
return location.GetLineSpan();
}

private static SyntaxNode FindLineDirecitive(SyntaxNode node)
{
while (node != null)
{
if (LineDirective(node) is { } lineDirective)
{
return lineDirective;
}
var directive = FindLineDirectiveOnSameLevel(node);

if (directive != null)
{
return directive;
}

node = node.Parent;
}
return null;
}

private static SyntaxNode FindLineDirectiveOnSameLevel(SyntaxNode node)
{
var childNodes = node.Parent.ChildNodes().ToArray();
var index = -1;
for (var i = 0; i < childNodes.Count(); i++)
{
if (childNodes[i] == node)
{
index = i;
break;
}
}

if (index == -1)
{
return null;
}

for (var j = index; j >= 0; j--)
{
if (LineDirective(childNodes[j]) is { } lineDirective)
{
return lineDirective;
}
}

return null;
}

private static SyntaxNode LineDirective(SyntaxNode node) =>
node.DescendantNodes(_ => true, true).FirstOrDefault(x => x.IsKind(SyntaxKind.LineDirectiveTrivia)
|| x.IsKind(SyntaxKindEx.LineSpanDirectiveTrivia));
}
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,7 @@ private static SymbolReferenceInfo.Types.SymbolReference GetSymbolReference(IRea
{
var reference = references[i];
if (!reference.IsDeclaration
&& reference.Identifier.GetLocation().GetMappedLineSpanIfAvailable() is var mappedLineSpan
// Syntax tree can contain elements from external files (e.g. razor imports files)
// We need to make sure that we don't count these elements.
&& reference.Identifier.GetLocation().GetMappedLineSpanIfAvailable(reference.Identifier) is var mappedLineSpan
&& string.Equals(mappedLineSpan.Path, filePath, StringComparison.OrdinalIgnoreCase))
{
symbolReference.Reference.Add(GetTextRange(mappedLineSpan));
Expand All @@ -140,7 +138,7 @@ private static SymbolReferenceInfo.Types.SymbolReference GetSymbolReference(IRea
for (var i = 0; i < references.Count; i++)
{
if (references[i].IsDeclaration
&& references[i].Identifier.GetLocation().GetMappedLineSpanIfAvailable() is var mappedLineSpan
&& references[i].Identifier.GetLocation().GetMappedLineSpanIfAvailable(references[i].Identifier) is var mappedLineSpan
&& string.Equals(mappedLineSpan.Path, filePath, StringComparison.OrdinalIgnoreCase))
{
return mappedLineSpan;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ token switch

protected TokenInfo TokenInfo(SyntaxToken token, TokenType tokenType)
{
var span = token.GetLocation().GetMappedLineSpanIfAvailable();
var span = token.GetLocation().GetMappedLineSpanIfAvailable(token);
return tokenType == TokenType.UnknownTokentype
|| (string.IsNullOrWhiteSpace(token.Text) && tokenType != TokenType.StringLiteral)
|| !(string.IsNullOrWhiteSpace(filePath) || string.Equals(span.Path, filePath, StringComparison.OrdinalIgnoreCase))
Expand Down Expand Up @@ -205,7 +205,7 @@ protected TriviaClassifierBase(string filePath)
new()
{
TokenType = tokenType,
TextRange = GetTextRange(Location.Create(tree, span).GetLineSpan())
TextRange = GetTextRange(Location.Create(tree, span).GetMappedLineSpanIfAvailable())
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,27 +102,25 @@ public void Verify_Razor()
.And.Contain((58, 58), "ks")
.And.Contain((59, 59), "ksns")
.And.Contain((60, 60), "ksnss")
.And.Contain((66, 66), "kkks")
.And.Contain((62, 66), "c")
.And.Contain((66, 66), "kkkcsc")
.And.Contain((68, 68), "kktkkkkkts")
.And.Contain((84, 84), "nt")
.And.Contain((85, 85), "ntn")
.And.Contain((86, 86), "nknkk")
.And.Contain((87, 87), "nt")
.And.Contain((91, 91), "nnn")
.And.Contain((92, 92), "nnn")
.And.Contain((93, 93), "nttn")
.And.Contain((70, 70), "c")
.And.Contain((71, 73), "c")
.And.Contain((74, 74), "c")
.And.Contain((84, 84), "t")
.And.Contain((85, 85), "tn")
.And.Contain((86, 86), "knkk")
.And.Contain((87, 87), "t")
.And.Contain((91, 91), "nn")
.And.Contain((92, 92), "nn")
.And.Contain((93, 93), "ttn")
.And.Contain((98, 98), "kn")
.And.Contain((99, 99), "kn")
.And.Contain((100, 100), "kn")
.And.Contain((215, 215), "c")
.And.Contain((216, 216), "c")
.And.Contain((217, 217), "c")
.And.Contain((246, 250), "c")
.And.Contain((246, 250), "c")
.And.Contain((250, 250), "cc")
.And.Contain((254, 254), "c")
.And.Contain((255, 257), "c")
.And.Contain((258, 258), "c");
.And.Contain((106, 106), "c")
.And.Contain((107, 107), "c")
.And.Contain((108, 108), "c");
});
}

Expand Down

0 comments on commit 8fd808c

Please sign in to comment.