Version Used:
VS 2019 preview 3
Warning AD0001 Analyzer 'Microsoft.CodeAnalysis.CSharp.Diagnostics.AddBraces.CSharpAddBracesDiagnosticAnalyzer' threw an exception of type 'System.InvalidOperationException' with message 'Unexpected true'.
Microsoft.CodeAnalysis.CSharp.Diagnostics.AddBraces.CSharpAddBracesDiagnosticAnalyzer' threw the following exception:
'Exception occurred with following context:
Compilation: SwitchToSource.CLI
SyntaxTree: C:\Users\Documents\Sources\Command.List.cs
SyntaxNode: else System.Console.WriteLine($" ... [ElseClauseSyntax]@[2781..2931) (54,40)-(55,144)
System.InvalidOperationException: Unexpected true
at Roslyn.Utilities.Contract.ThrowIfTrue(Boolean condition, String message)
at Microsoft.CodeAnalysis.Shared.Utilities.CommonFormattingHelpers.AppendTextBetween(SyntaxToken token1, SyntaxToken token2, StringBuilder builder)
at Microsoft.CodeAnalysis.CSharp.Utilities.FormattingRangeHelper.AreTwoTokensOnSameLine(SyntaxToken token1, SyntaxToken token2)
at Microsoft.CodeAnalysis.CSharp.Diagnostics.AddBraces.CSharpAddBracesDiagnosticAnalyzer.IsConsideredMultiLine(SyntaxNode statement, SyntaxNode embeddedStatement)
at Microsoft.CodeAnalysis.CSharp.Diagnostics.AddBraces.CSharpAddBracesDiagnosticAnalyzer.AnalyzeNode(SyntaxNodeAnalysisContext context)
at Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.<>c__50`1.<ExecuteSyntaxNodeAction>b__50_0(ValueTuple`2 data)
at Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.ExecuteAndCatchIfThrows_NoLock[TArg](DiagnosticAnalyzer analyzer, Action`1 analyze, TArg argument, Nullable`1 info)
-----
'.
The code around the error (The line comments are not in the original code)
packageToDisplayList.ForEach(listedPackage => // line 48
{
System.Console.WriteLine($"- {listedPackage.PackageId}");
foreach (var versionInfo in listedPackage.Versions)
{
if (versionInfo.Reason == NonSwitchableReason.None)
System.Console.WriteLine($" * {versionInfo.Version} [{versionInfo.State}]"); // line 54
else
System.Console.WriteLine($" * {versionInfo.Version} [{versionInfo.State}: {versionInfo.Reason}]");
}
});
Reported at DC (link) Priority 1
Hmm, I couldn't trigger the error with code provided (and setting preferbraces to WhenMultiline), @meziantou is this something repro consistently for you?
FYI @sharwell who might have some insight here
I don't repro with VS 2019 preview 5. So, maybe it's already fixed...
Closed sicne we are unable to repro this issue. Please reopen and provide us more information on how to repro if you are still seeing it.
I see that this was closed; however I am receiving the same errors on 16.0.4. On a large solution, I am receiving ~150 warnings with this error. It seems to be occurring around nested if statements where the deeper if/else is single line. Thanks,
I created a pull request that addresses the issue. The resolution should be reviewed, but the issue was traced: The AreTwoTokensOnSameLine method is called with the two parameters being equal. There are no guards or checks for the first and last being equal until the AppendTextBetween method which contractually throws. If they are indeed the same token, then they are certainly on the same line.
I'm getting the same issue in VisualStudio.16.Release/16.1.2+29001.49, on two if statements with one-line else statements.
```C#
private void Advance() {
try {
int next = input.Read();
if (next >= 0)
currentChar = (char)next;
else
currentChar = '\0';
} catch (IOException) {
currentChar = '\0';
}
}
```C#
public Label DefaultTarget() {
if (targets.Count > 0)
return targets[targets.Count - 1];
else
return null;
}
@effleurager Thanks for reporting the issue! I have tried the following code using the version you specified as well as the latest in master, but still couldn't repro the crash :(
What's the codestyle preference you set for braces (I did try all three options though)? Are you able to hit the crash with the code below?
class Program
{
string[] targets;
private Program input;
private char currentChar;
public string DefaultTarget()
{
if (targets.Count() > 0)
return targets[targets.Count() - 1];
else
return null;
}
public void Advance()
{
try {
int next = input.Read();
if (next >= 0)
currentChar = (char)next;
else
currentChar = '\0';
} catch (IOException) {
currentChar = '\0';
}
}
char Read() => 'a';
}

I'm hitting this issue for a long time now, so i want to help to completely track down the issue, so tell me if you need any additional info to figure this out (VS 16.1.2).
i got a crash log for you:
Severity Code Description Project File Line Suppression State Detail Description
Warning AD0001 Analyzer 'Microsoft.CodeAnalysis.CSharp.Diagnostics.AddBraces.CSharpAddBracesDiagnosticAnalyzer' threw an exception of type 'System.InvalidOperationException' with message 'Unexpected true'. WebLibCore 1 Active Analyzer 'Microsoft.CodeAnalysis.CSharp.Diagnostics.AddBraces.CSharpAddBracesDiagnosticAnalyzer' threw the following exception:
'Exception occurred with following context:
Compilation: WebLibCore
SyntaxTree: C:\Workspace\Developments\Work\Libraries\WebLibCore\WebLibCore\Backend\WLCBELogHelper.cs
SyntaxNode: else return await BELogAsync(WLCBELogType ... [ElseClauseSyntax]@[2000..2158) (49,16)-(50,152)
System.InvalidOperationException: Unexpected true
at Roslyn.Utilities.Contract.ThrowIfTrue(Boolean condition, String message)
at Microsoft.CodeAnalysis.Shared.Utilities.CommonFormattingHelpers.AppendTextBetween(SyntaxToken token1, SyntaxToken token2, StringBuilder builder)
at Microsoft.CodeAnalysis.CSharp.Utilities.FormattingRangeHelper.AreTwoTokensOnSameLine(SyntaxToken token1, SyntaxToken token2)
at Microsoft.CodeAnalysis.CSharp.Diagnostics.AddBraces.CSharpAddBracesDiagnosticAnalyzer.IsConsideredMultiLine(SyntaxNode statement, SyntaxNode embeddedStatement)
at Microsoft.CodeAnalysis.CSharp.Diagnostics.AddBraces.CSharpAddBracesDiagnosticAnalyzer.AnalyzeNode(SyntaxNodeAnalysisContext context)
at Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.<>c__50`1.<ExecuteSyntaxNodeAction>b__50_0(ValueTuple`2 data)
at Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.ExecuteAndCatchIfThrows_NoLock[TArg](DiagnosticAnalyzer analyzer, Action`1 analyze, TArg argument, Nullable`1 info)
-----
'.
and this is the code section that reported in crash log:

(if you need more code let me know)
and this is my code style rule set

i'm waiting for your response if you need additional info on anything just let me know.
I have been looking into this issue, I can reproduce the exception while debugging the unit tests by manually bypassing a certain check, and from my testing a simple fix _does_ solve the issue. That said I am unable to understand why/how a SyntaxToken reaches the symptomatic state.
Within the CSharpAddBracesDiagnosticAnalyzer.IsConsideredMultiLine method, multiple checks are performed with specific tokens to identify if the overall statement should be considered as spanning multiple lines. The third such check (in the case of a non-braced else clause) will always provide the _same_ token as both parameters to theFomattingRangeHelper.AreTwoTokensOnSameLine method.
In normal operation, this method uses the SyntaxTree's text to verify if the two tokens are on the same line, in which case checking the same token is unnecessary, but works fine. But (here is the state I don't understand) if the token's SyntaxTree is null or the TryGetText method fails, then an alternate methodology is used which _contractually_ throws an exception when the tokens are the same.
I assume there must be a condition or state where a token's SyntaxTree is null or the TryGetText method will fail, otherwise this code would not have been written - but I do not know how to reproduce this state.
All of the relevant code:
From CSharpAddBracesDiagnosticAnalyzer.IsConsideredMultiLine:
...
// Check the part of the statement preceding the embedded statement (bullet 1)
var lastTokenBeforeEmbeddedStatement = embeddedStatement.GetFirstToken().GetPreviousToken();
if (!FormattingRangeHelper.AreTwoTokensOnSameLine(statement.GetFirstToken(), lastTokenBeforeEmbeddedStatement))
{
// The part of the statement preceding the embedded statement does not fit on one line. Examples:
//
// for (int i = 0; // <-- The initializer/condition/increment are on separate lines
// i < 10;
// i++)
// SomeMethod();
return true;
}
...
With a statement like else \n foo(); the first token and the embedded statement's previous token will both be the same 'else' token.
The main code in question is in FomattingRangeHelper:
public static bool AreTwoTokensOnSameLine(SyntaxToken token1, SyntaxToken token2)
{
var tree = token1.SyntaxTree;
if (tree != null && tree.TryGetText(out var text)) // <-- When / how does this fail?
{
return text.AreOnSameLine(token1, token2);
}
// This call eventually throws if token1 == token2
return !CommonFormattingHelpers.GetTextBetween(token1, token2).ContainsLineBreak();
}
How do we get a token with no SyntaxTree or failed TryGetText call?
Lastly, the simple fix is to update the AreTwoTokensOnSameLine method to include a preemptive check to see if the tokens are equal - since if they are equal then they are certainly on the same line:
public static bool AreTwoTokensOnSameLine(SyntaxToken token1, SyntaxToken token2)
{
if(token1 == token2) return true;
...
@genlu This is my .editorconfig file, but it seems that the issue is rather temperamental as I cannot reproduce the issue on the same initial code or your boiled down class, despite running the same version.
but it seems that the issue is rather temperamental as I cannot reproduce the issue on the same initial code or your boiled down class, despite running the same version
Yeah, that's what's been puzzling me. There's seems to be some nondeterminism of this bug.
@Andrew-Hanlon Thanks for the detailed analysis! @CyrusNajmabadi do you know in what scenario we might get null from token.SyntaxTree?
Haven't read everything. But is the token a default token?
var tree = token1.SyntaxTree;
if (tree != null && tree.TryGetText(out var text)) // <-- When / how does this fail?
I'm not sure why we woudl think this would every necessarily succeed. i.e. just because you have the tree, the text may still be dumped from memory. For example, if this was just some forked tree or analyzing some old snapshot that the main VS buffer had moved forward from.
--
@jasonmalinowski What's our rules/invariants around TryGetText? I don't think we have a guarantee around it that would make it work for something like this.
@CyrusNajmabadi Thank you, that's good to know. Would you know if there is a way to set-up a unit test for such a scenario (dumped from memory for example)?
In any case, I know my suggested fix solves the issue. I closed a previous PR as I could not produce a unit test to capture the scenario, but I can open a new one with some of these details.
@CyrusNajmabadi Thank you, that's good to know. Would you know if there is a way to set-up a unit test for such a scenario (dumped from memory for example)?
That's a great question. I imagine (and maybe @jasonmalinowski could help here), but you should be able to just work with teh workspace, get the snapshot for the existing buffer, then actually edit/close the buffer, then GC a lot... maybe you'd see it happen?
I'm not really sure where we ever landed in terms of hte invariants around TryGetXXX (esp. around active/open docs). So it's hard to say what would be necessary to get TryGetXXX to fail.
A little bit more debugging information:
I was able to debug this situation by running the Roslyn solution and attaching the debugger to the ServiceHub.RoslynCodeAnalysisService32.exe process.
When the 'error' state was hit, I was able to see in the immediate window that indeed it is the TryGetText method that is failing.
The stacktrace is below:
Microsoft.CodeAnalysis.Workspaces.dll!Microsoft.CodeAnalysis.Shared.Utilities.CommonFormattingHelpers.AppendTextBetween(Microsoft.CodeAnalysis.SyntaxToken token1, Microsoft.CodeAnalysis.SyntaxToken token2, System.Text.StringBuilder builder) Line 168 C#
Microsoft.CodeAnalysis.Workspaces.dll!Microsoft.CodeAnalysis.Shared.Utilities.CommonFormattingHelpers.GetTextBetween(Microsoft.CodeAnalysis.SyntaxToken token1, Microsoft.CodeAnalysis.SyntaxToken token2) Line 160 C#
Microsoft.CodeAnalysis.CSharp.Workspaces.dll!Microsoft.CodeAnalysis.CSharp.Utilities.FormattingRangeHelper.AreTwoTokensOnSameLine(Microsoft.CodeAnalysis.SyntaxToken token1, Microsoft.CodeAnalysis.SyntaxToken token2) Line 299 C#
Microsoft.CodeAnalysis.CSharp.Features.dll!Microsoft.CodeAnalysis.CSharp.Diagnostics.AddBraces.CSharpAddBracesDiagnosticAnalyzer.IsConsideredMultiLine(Microsoft.CodeAnalysis.SyntaxNode statement, Microsoft.CodeAnalysis.SyntaxNode embeddedStatement) Line 172 C#
Microsoft.CodeAnalysis.CSharp.Features.dll!Microsoft.CodeAnalysis.CSharp.Diagnostics.AddBraces.CSharpAddBracesDiagnosticAnalyzer.AnalyzeNode(Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext context) Line 95 C#
Microsoft.CodeAnalysis.dll!Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.ExecuteSyntaxNodeAction.AnonymousMethod__50_0((System.Action<Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext> action, Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext context) data) Line 726 C#
Microsoft.CodeAnalysis.dll!Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.ExecuteAndCatchIfThrows_NoLock<System.ValueTuple<System.Action<Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext>, Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext>>(Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer analyzer, System.Action<(System.Action<Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext>, Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext)> analyze, (System.Action<Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext>, Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext) argument, Microsoft.CodeAnalysis.Diagnostics.AnalysisContextInfo? info) Line 1384 C#
Microsoft.CodeAnalysis.dll!Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.ExecuteAndCatchIfThrows<System.ValueTuple<System.Action<Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext>, Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext>>(Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer analyzer, System.Action<(System.Action<Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext>, Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext)> analyze, (System.Action<Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext>, Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext) argument, Microsoft.CodeAnalysis.Diagnostics.AnalysisContextInfo? info) Line 1353 C#
Microsoft.CodeAnalysis.dll!Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.ExecuteSyntaxNodeAction<Microsoft.CodeAnalysis.CSharp.SyntaxKind>(Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalyzerAction<Microsoft.CodeAnalysis.CSharp.SyntaxKind> syntaxNodeAction, Microsoft.CodeAnalysis.SyntaxNode node, Microsoft.CodeAnalysis.ISymbol containingSymbol, Microsoft.CodeAnalysis.SemanticModel semanticModel, System.Action<Microsoft.CodeAnalysis.Diagnostic> addDiagnostic, System.Func<Microsoft.CodeAnalysis.Diagnostic, bool> isSupportedDiagnostic, Microsoft.CodeAnalysis.Diagnostics.AnalysisState.SyntaxNodeAnalyzerStateData analyzerStateOpt) Line 724 C#
Microsoft.CodeAnalysis.dll!Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.ExecuteSyntaxNodeActions<Microsoft.CodeAnalysis.CSharp.SyntaxKind>(Microsoft.CodeAnalysis.SyntaxNode node, System.Collections.Generic.IDictionary<Microsoft.CodeAnalysis.CSharp.SyntaxKind, System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalyzerAction<Microsoft.CodeAnalysis.CSharp.SyntaxKind>>> nodeActionsByKind, Microsoft.CodeAnalysis.ISymbol containingSymbol, Microsoft.CodeAnalysis.SemanticModel model, System.Func<Microsoft.CodeAnalysis.SyntaxNode, Microsoft.CodeAnalysis.CSharp.SyntaxKind> getKind, System.Action<Microsoft.CodeAnalysis.Diagnostic> addDiagnostic, System.Func<Microsoft.CodeAnalysis.Diagnostic, bool> isSupportedDiagnostic, Microsoft.CodeAnalysis.Diagnostics.AnalysisState.SyntaxNodeAnalyzerStateData analyzerStateOpt) Line 1180 C#
Microsoft.CodeAnalysis.dll!Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.ExecuteSyntaxNodeActions<Microsoft.CodeAnalysis.CSharp.SyntaxKind>(System.Collections.Generic.IEnumerable<Microsoft.CodeAnalysis.SyntaxNode> nodesToAnalyze, System.Collections.Generic.IDictionary<Microsoft.CodeAnalysis.CSharp.SyntaxKind, System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalyzerAction<Microsoft.CodeAnalysis.CSharp.SyntaxKind>>> nodeActionsByKind, Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer analyzer, Microsoft.CodeAnalysis.ISymbol containingSymbol, Microsoft.CodeAnalysis.SemanticModel model, System.Func<Microsoft.CodeAnalysis.SyntaxNode, Microsoft.CodeAnalysis.CSharp.SyntaxKind> getKind, System.Action<Microsoft.CodeAnalysis.Diagnostic> addDiagnostic, System.Func<Microsoft.CodeAnalysis.Diagnostic, bool> isSupportedDiagnostic, Microsoft.CodeAnalysis.Diagnostics.AnalysisState.SyntaxNodeAnalyzerStateData analyzerStateOpt) Line 1159 C#
Microsoft.CodeAnalysis.dll!Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.ExecuteSyntaxNodeActionsCore<Microsoft.CodeAnalysis.CSharp.SyntaxKind>(System.Collections.Generic.IEnumerable<Microsoft.CodeAnalysis.SyntaxNode> nodesToAnalyze, System.Collections.Generic.IDictionary<Microsoft.CodeAnalysis.CSharp.SyntaxKind, System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalyzerAction<Microsoft.CodeAnalysis.CSharp.SyntaxKind>>> nodeActionsByKind, Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer analyzer, Microsoft.CodeAnalysis.ISymbol containingSymbol, Microsoft.CodeAnalysis.SemanticModel model, System.Func<Microsoft.CodeAnalysis.SyntaxNode, Microsoft.CodeAnalysis.CSharp.SyntaxKind> getKind, Microsoft.CodeAnalysis.Text.TextSpan filterSpan, Microsoft.CodeAnalysis.Diagnostics.AnalysisState.SyntaxNodeAnalyzerStateData analyzerStateOpt, bool isGeneratedCode) Line 1129 C#
Microsoft.CodeAnalysis.dll!Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.TryExecuteSyntaxNodeActions<Microsoft.CodeAnalysis.CSharp.SyntaxKind>(System.Collections.Generic.IEnumerable<Microsoft.CodeAnalysis.SyntaxNode> nodesToAnalyze, System.Collections.Generic.IDictionary<Microsoft.CodeAnalysis.CSharp.SyntaxKind, System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalyzerAction<Microsoft.CodeAnalysis.CSharp.SyntaxKind>>> nodeActionsByKind, Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer analyzer, Microsoft.CodeAnalysis.SemanticModel model, System.Func<Microsoft.CodeAnalysis.SyntaxNode, Microsoft.CodeAnalysis.CSharp.SyntaxKind> getKind, Microsoft.CodeAnalysis.Text.TextSpan filterSpan, Microsoft.CodeAnalysis.SyntaxReference declaration, int declarationIndex, Microsoft.CodeAnalysis.ISymbol declaredSymbol, Microsoft.CodeAnalysis.Diagnostics.AnalysisScope analysisScope, Microsoft.CodeAnalysis.Diagnostics.AnalysisState analysisStateOpt, bool isGeneratedCode) Line 1098 C#
Microsoft.CodeAnalysis.dll!Microsoft.CodeAnalysis.Diagnostics.AnalyzerDriver<Microsoft.CodeAnalysis.CSharp.SyntaxKind>.TryExecuteDeclaringReferenceActions.__executeNodeActionsByKind|2(Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer analyzer, System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.SyntaxNode> nodesToAnalyze, Microsoft.CodeAnalysis.Diagnostics.AnalyzerDriver<Microsoft.CodeAnalysis.CSharp.SyntaxKind>.GroupedAnalyzerActions groupedActions) Line 1892 C#
Microsoft.CodeAnalysis.dll!Microsoft.CodeAnalysis.Diagnostics.AnalyzerDriver<Microsoft.CodeAnalysis.CSharp.SyntaxKind>.TryExecuteDeclaringReferenceActions.__executeNodeActions|1() Line 1881 C#
Microsoft.CodeAnalysis.dll!Microsoft.CodeAnalysis.Diagnostics.AnalyzerDriver<Microsoft.CodeAnalysis.CSharp.SyntaxKind>.TryExecuteDeclaringReferenceActions(Microsoft.CodeAnalysis.SyntaxReference decl, int declarationIndex, Microsoft.CodeAnalysis.Diagnostics.SymbolDeclaredCompilationEvent symbolEvent, Microsoft.CodeAnalysis.Diagnostics.AnalysisScope analysisScope, Microsoft.CodeAnalysis.Diagnostics.AnalysisState analysisStateOpt, Microsoft.CodeAnalysis.Diagnostics.AnalyzerDriver<Microsoft.CodeAnalysis.CSharp.SyntaxKind>.GroupedAnalyzerActions additionalPerSymbolActions, bool shouldExecuteSyntaxNodeActions, bool shouldExecuteOperationActions, bool shouldExecuteCodeBlockActions, bool shouldExecuteOperationBlockActions, bool isInGeneratedCode, System.Threading.CancellationToken cancellationToken) Line 1848 C#
Microsoft.CodeAnalysis.dll!Microsoft.CodeAnalysis.Diagnostics.AnalyzerDriver<Microsoft.CodeAnalysis.CSharp.SyntaxKind>.TryExecuteDeclaringReferenceActions(Microsoft.CodeAnalysis.Diagnostics.SymbolDeclaredCompilationEvent symbolEvent, Microsoft.CodeAnalysis.Diagnostics.AnalysisScope analysisScope, Microsoft.CodeAnalysis.Diagnostics.AnalysisState analysisStateOpt, bool isGeneratedCodeSymbol, Microsoft.CodeAnalysis.Diagnostics.AnalyzerActions additionalPerSymbolActionsOpt, System.Threading.CancellationToken cancellationToken) Line 1739 C#
Microsoft.CodeAnalysis.dll!Microsoft.CodeAnalysis.Diagnostics.AnalyzerDriver.TryProcessSymbolDeclaredAsync(Microsoft.CodeAnalysis.Diagnostics.SymbolDeclaredCompilationEvent symbolEvent, Microsoft.CodeAnalysis.Diagnostics.AnalysisScope analysisScope, Microsoft.CodeAnalysis.Diagnostics.AnalysisState analysisStateOpt, System.Threading.CancellationToken cancellationToken) Line 1060 C#
Microsoft.CodeAnalysis.dll!Microsoft.CodeAnalysis.Diagnostics.AnalyzerDriver.TryProcessEventCoreAsync(Microsoft.CodeAnalysis.Diagnostics.CompilationEvent e, Microsoft.CodeAnalysis.Diagnostics.AnalysisScope analysisScope, Microsoft.CodeAnalysis.Diagnostics.AnalysisState analysisStateOpt, System.Threading.CancellationToken cancellationToken) Line 1001 C#
Microsoft.CodeAnalysis.dll!Microsoft.CodeAnalysis.Diagnostics.AnalyzerDriver.ProcessEventAsync(Microsoft.CodeAnalysis.Diagnostics.CompilationEvent e, Microsoft.CodeAnalysis.Diagnostics.AnalysisScope analysisScope, Microsoft.CodeAnalysis.Diagnostics.AnalysisState analysisStateOpt, System.Threading.CancellationToken cancellationToken) Line 935 C#
Microsoft.CodeAnalysis.dll!Microsoft.CodeAnalysis.Diagnostics.AnalyzerDriver.ProcessCompilationEventsCoreAsync(Microsoft.CodeAnalysis.Diagnostics.AnalysisScope analysisScope, Microsoft.CodeAnalysis.Diagnostics.AnalysisState analysisStateOpt, bool prePopulatedEventQueue, System.Threading.CancellationToken cancellationToken) Line 922 C#
Likewise by applying the equality check fix above, this exception is no longer hit.
Without looking at the code, the only rule I'd be comfortable saying about TryGetText is you shouldn't use it. :smile: Now to back to trying to be useful.
@jasonmalinowski What's our rules/invariants around TryGetText? I don't think we have a guarantee around it that would make it work for something like this.
I don't think there are formally documented rules. The method is only intended for optimizations where you can potentially fast-path something. I suspect you're right that this could fail if you have somebody rewriting a tree, and we haven't yet computed text, or if we did were only holding text lazily. Even if there are "rules" I assume things would get complicated: I would assume that a syntax tree that didn't have realized text would fail TryGetText, but once somebody called GetText() (which is possibly a different extension in the same process!) then maybe it'd work.
If we wanted a unit test to cover a case I wouldn't want the unit test trying to reproduce a "conditions where we know this will fail" because the test is tied to an implementation detail in a different system. I'd say either have the test create it's own derived version of SyntaxTree that will fail TryGetText, or just test the underlying methods there that they behave the same and trust you've got both paths right.
I don't think there are formally documented rules. The method is only intended for optimizations where you can potentially fast-path something.
Yeha, the only rule i've ever had is: this is safe if you are certain someone higher in your calltree grabbed this thing and put it in a local**
--
** And even then, you probably need a GC.KeepAlive. And even then... why are you not just passing this value downstream to the people who clearly need it?
Thanks for the insight all. So my proposal is that I will create a PR that includes the fix plus a new unit test that covers the AreTwoTokensOnSameLine helper method using a mocked SyntaxNode/Tree that simulates the currently failing case.
Most helpful comment
Thanks for the insight all. So my proposal is that I will create a PR that includes the fix plus a new unit test that covers the
AreTwoTokensOnSameLinehelper method using a mocked SyntaxNode/Tree that simulates the currently failing case.