public void AnalyzeFile(AdditionalText file, CompilationAnalysisContext context) { var text = file.GetText(); var content = text.ToString(); foreach (Match match in Regex.Matches(content)) { context.ReportDiagnostic(ExternalDiagnostic.Create(RuleValidateRequest, file.Path, text.Lines.GetLinePosition(match.Index).Line + 1, match.Value)); } }
private static void VerifyAppManifest(AdditionalFileAnalysisContext context, AdditionalText appManifest) { SourceText?appManifestXml = appManifest.GetText(context.CancellationToken); if (appManifestXml is null) { return; } // If the manifest file is corrupt - let the build fail XmlDocument doc = new(); try { doc.LoadXml(appManifestXml.ToString()); } catch { // Invalid xml, don't care return; } XmlNamespaceManager nsmgr = new(doc.NameTable); nsmgr.AddNamespace("v1", "urn:schemas-microsoft-com:asm.v1"); nsmgr.AddNamespace("v3", "urn:schemas-microsoft-com:asm.v3"); nsmgr.AddNamespace("v3ws", "http://schemas.microsoft.com/SMI/2005/WindowsSettings"); if (doc.DocumentElement.SelectSingleNode("//v3:application/v3:windowsSettings/v3ws:dpiAware", nsmgr) is not null) { switch (context.Compilation.Language) { case LanguageNames.CSharp: context.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.s_migrateHighDpiSettings_CSharp, Location.None, appManifest.Path, ApplicationConfig.PropertyNameCSharp.HighDpiMode)); break; case LanguageNames.VisualBasic: context.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.s_migrateHighDpiSettings_VB, Location.None, appManifest.Path, ApplicationConfig.PropertyNameVisualBasic.HighDpiMode)); break; default: throw new NotSupportedException(); } } }
#pragma warning disable RS1012 // Start action has no registered actions. bool LoadOptions(CompilationStartAnalysisContext context, AdditionalText mdkOptions) #pragma warning restore RS1012 // Start action has no registered actions. { try { var content = mdkOptions.GetText(context.CancellationToken); var document = XDocument.Parse(content.ToString()); var ignoredFolders = document.Element("mdk")?.Elements("ignore").SelectMany(e => e.Elements("folder")); var ignoredFiles = document.Element("mdk")?.Elements("ignore").SelectMany(e => e.Elements("file")).ToArray(); var basePath = Path.GetDirectoryName(mdkOptions.Path).TrimEnd('\\') + "\\..\\"; if (!basePath.EndsWith("\\")) { basePath += "\\"; } _optionException = null; _basePath = new Uri(basePath); _namespaceName = (string)document.Element("mdk")?.Element("namespace") ?? DefaultNamespaceName; _ignoredFolders.Clear(); _ignoredFiles.Clear(); if (ignoredFolders != null) { foreach (var folderElement in ignoredFolders) { var folder = folderElement.Value; if (!folder.EndsWith("\\")) { _ignoredFolders.Add(new Uri(_basePath, new Uri(folder + "\\", UriKind.RelativeOrAbsolute))); } else { _ignoredFolders.Add(new Uri(_basePath, new Uri(folder, UriKind.RelativeOrAbsolute))); } } } if (ignoredFiles != null) { foreach (var fileElement in ignoredFiles) { var file = fileElement.Value; _ignoredFiles.Add(new Uri(_basePath, new Uri(file, UriKind.RelativeOrAbsolute))); } } return(true); } catch (Exception e) { _optionException = e; return(false); } }
private SourceText GenerateSourceForAdditionalFile(AdditionalText file, CancellationToken cancellationToken) { Interlocked.Increment(ref _additionalFilesConvertedCount); // We're going to "comment" out the contents of the file when generating this var sourceText = file.GetText(cancellationToken); Contract.ThrowIfNull(sourceText, "Failed to fetch the text of an additional file."); var changes = sourceText.Lines.SelectAsArray(l => new TextChange(new TextSpan(l.Start, length: 0), "// ")); var generatedText = sourceText.WithChanges(changes); return(SourceText.From(generatedText.ToString(), encoding: Encoding.UTF8)); }
public SourceGeneratorProjectItem(string basePath, string filePath, string relativePhysicalPath, string fileKind, AdditionalText additionalText, string?cssScope) { BasePath = basePath; FilePath = filePath; RelativePhysicalPath = relativePhysicalPath; _fileKind = fileKind; AdditionalText = additionalText; CssScope = cssScope; var text = AdditionalText.GetText(); if (text is not null) { RazorSourceDocument = new SourceTextRazorSourceDocument(AdditionalText.Path, relativePhysicalPath, text); } }
/// <summary> /// Initializes a new instance of the <see cref="ResourceModel"/> class. /// </summary> /// <param name="source">The source information.</param> public ResourceModel(AdditionalText source) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (string.IsNullOrWhiteSpace(source.Path)) { throw new InvalidOperationException(@$ "Cannot derive class name from invalid path " "{source.Path}" ""); } _propertiesCode = ProcessProperties(source.GetText()?.ToString()); ClassName = Path.GetFileNameWithoutExtension(source.Path); }
private void CheckMainConfigAndLocations(string attribute, string defaultValue, Func <string, bool> isGoodValue, DiagnosticDescriptor diagnosticDescriptor, XElement systemWeb, XElement lastFoundElement, string subElement, XDocument doc, AdditionalText file, CompilationAnalysisContext context) { var subElementNode = GetElement(systemWeb, ref lastFoundElement, subElement); var value = CheckAttribute(subElementNode, attribute, defaultValue, isGoodValue, diagnosticDescriptor, lastFoundElement, file, context); // if the value is bad in the main config element, don't report it if is set to bad again in every location if (!isGoodValue(value)) { return; } var locations = doc.Element("configuration")?.Elements("location"); if (locations == null) { return; } foreach (var location in locations) { lastFoundElement = location; var pages = GetElement(location, ref lastFoundElement, "system.web", subElement); CheckAttribute(pages, attribute, value, isGoodValue, diagnosticDescriptor, lastFoundElement, file, context); } }
public Model.ConfigurationFile Parse(AdditionalText src, string basePath, string workingDirectory) { var file = new Model.ConfigurationFile(); //Set the base configuration file properties file.Source = src; file.BaseConfigurationPath = src.Path; file.BaseConfigurationDocument = XDocument.Load(file.BaseConfigurationPath, LoadOptions.SetLineInfo); //Construct the path to the prod transform file var productionTransform = string.IsNullOrEmpty(RuleOptions.ProductionBuildConfiguration) ? null : Path.Combine( Path.GetDirectoryName(file.BaseConfigurationPath) , string.Format("{0}.{1}{2}", Path.GetFileNameWithoutExtension(file.BaseConfigurationPath) , RuleOptions.ProductionBuildConfiguration, Path.GetExtension(file.BaseConfigurationPath))); //If transform file exists, run the transform and set the prod document if (!string.IsNullOrEmpty(productionTransform) && File.Exists(productionTransform)) { //Set the prod transform path file.ProductionTransformPath = productionTransform; //Set the location of the transformed file file.ProductionConfigurationPath = Path.Combine(workingDirectory, productionTransform.Replace(basePath, "").Trim(Path.DirectorySeparatorChar)); if (_shouldUpdate.Execute(file)) { _transformer.Execute(file); } //Parse the prod transform xml file.ProductionConfigurationDocument = XDocument.Load(file.ProductionConfigurationPath, LoadOptions.SetLineInfo); } else { //No transform file exists, set the defaults file.ProductionTransformPath = null; file.ProductionConfigurationPath = file.BaseConfigurationPath; file.ProductionConfigurationDocument = file.BaseConfigurationDocument; } //Set the parse timestamp file.Created = DateTime.Now; return(file); }
public override void Initialize(AnalysisContext context) { context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.EnableConcurrentExecution(); context.RegisterCompilationStartAction(compilationStartContext => { // Find the additional file with the terms. ImmutableArray <AdditionalText> additionalFiles = compilationStartContext.Options.AdditionalFiles; AdditionalText termsFile = additionalFiles.FirstOrDefault(file => Path.GetFileName(file.Path).Equals("Terms.xml")); if (termsFile != null) { HashSet <string> terms = new HashSet <string>(); SourceText fileText = termsFile.GetText(compilationStartContext.CancellationToken); // Write the additional file back to a stream. MemoryStream stream = new MemoryStream(); using (StreamWriter writer = new StreamWriter(stream)) { fileText.Write(writer); } // Read all the <Term> elements to get the terms. XDocument document = XDocument.Load(stream); foreach (XElement termElement in document.Descendants("Term")) { terms.Add(termElement.Value); } // Check every named type for the invalid terms. compilationStartContext.RegisterSymbolAction(symbolAnalysisContext => { INamedTypeSymbol namedTypeSymbol = (INamedTypeSymbol)symbolAnalysisContext.Symbol; string symbolName = namedTypeSymbol.Name; foreach (string term in terms) { if (symbolName.Contains(term)) { symbolAnalysisContext.ReportDiagnostic( Diagnostic.Create(Rule, namedTypeSymbol.Locations[0], term)); } } }, SymbolKind.NamedType); } }); }
private static HashSet <string> ReadPublicSymbols(AdditionalText additionalFile) { HashSet <string> publicSymbols = new HashSet <string>(); foreach (var line in additionalFile.GetText().Lines) { var text = line.ToString(); if (!string.IsNullOrWhiteSpace(text)) { publicSymbols.Add(text); } } return(publicSymbols); }
internal static AnalyzerSettingsRegistry LoadSettings([NotNull] AnalyzerOptions options, CancellationToken cancellationToken) { Guard.NotNull(options, nameof(options)); AdditionalText settingsFileOrNull = options.AdditionalFiles.FirstOrDefault(file => IsSettingsFile(file.Path)); if (settingsFileOrNull != null) { SourceText fileText = settingsFileOrNull.GetText(cancellationToken); return(SafeReadSourceText(fileText, cancellationToken)); } return(AnalyzerSettingsRegistry.ImmutableEmpty); }
private SourceText GenerateSource(AdditionalText additionalFile, string scalarFieldTypeMappingProviderTypeName) { var configurationOptions = new Dictionary <string, string> { { "build_property.GraphQlClientGenerator_ClassPrefix", "SourceGenerated" }, { "build_property.GraphQlClientGenerator_ClassSuffix", "V2" }, { "build_property.GraphQlClientGenerator_IncludeDeprecatedFields", "true" }, { "build_property.GraphQlClientGenerator_CommentGeneration", "CodeSummary" }, { "build_property.GraphQlClientGenerator_FloatTypeMapping", "Double" }, { "build_property.GraphQlClientGenerator_BooleanTypeMapping", "Boolean" }, { "build_property.GraphQlClientGenerator_IdTypeMapping", "String" }, { "build_property.GraphQlClientGenerator_JsonPropertyGeneration", "Always" }, { "build_property.GraphQlClientGenerator_CustomClassMapping", "Query:Tibber|RootMutation:TibberMutation Consumption:ConsumptionEntry;Production:ProductionEntry" }, { "build_property.GraphQlClientGenerator_Headers", "Authorization:Basic XXX|X-REQUEST-ID:123456789" }, { "build_property.GraphQlClientGenerator_HttpMethod", "GET" }, { "build_property.GraphQlClientGenerator_EnumValueNaming", "CSharp" } }; if (scalarFieldTypeMappingProviderTypeName is not null) { configurationOptions.Add("build_property.GraphQlClientGenerator_ScalarFieldTypeMappingProvider", scalarFieldTypeMappingProviderTypeName); } var compilerAnalyzerConfigOptionsProvider = new CompilerAnalyzerConfigOptionsProvider(new CompilerAnalyzerConfigOptions(configurationOptions)); var compilation = CompilationHelper.CreateCompilation(null, "SourceGeneratorTestAssembly"); var additionalFiles = new List <AdditionalText> { _fileGraphQlSchema }; if (additionalFile is not null) { additionalFiles.Add(additionalFile); } var sourceGenerator = new GraphQlClientSourceGenerator(); var driver = CSharpGeneratorDriver.Create(new [] { sourceGenerator }, additionalFiles, optionsProvider: compilerAnalyzerConfigOptionsProvider); var csharpDriver = driver.RunGenerators(compilation); var runResult = csharpDriver.GetRunResult(); var results = runResult.Results; results.Length.ShouldBe(1); results[0].GeneratedSources.Length.ShouldBe(1); return(results[0].GeneratedSources[0].SourceText); }
/// <summary> /// Gets the settings. /// </summary> /// <param name="additionalText">The additional text.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>The <see cref="AnalyzersSettings"/></returns> internal static AnalyzersSettings GetSettings(AdditionalText additionalText, CancellationToken cancellationToken) { SourceText text = additionalText.GetText(cancellationToken); try { SettingsFile settingsRoot = JsonConvert.DeserializeObject <SettingsFile>(text.ToString()); return(settingsRoot.Settings); } catch (JsonException) { // Error deserializing the settings file, will return the default settings instead. } return(new AnalyzersSettings()); }
#pragma warning disable RS1012 // Start action has no registered actions. bool LoadOptions(CompilationStartAnalysisContext context, AdditionalText mdkOptions) #pragma warning restore RS1012 // Start action has no registered actions. { try { var content = mdkOptions.GetText(context.CancellationToken); var properties = MDKProjectOptions.Parse(content.ToString(), mdkOptions.Path); var basePath = Path.GetFullPath(Path.GetDirectoryName(mdkOptions.Path) ?? ".").TrimEnd('\\') + "\\..\\"; if (!basePath.EndsWith("\\")) { basePath += "\\"; } _basePath = new Uri(basePath); _namespaceName = properties.Namespace ?? DefaultNamespaceName; lock (_ignoredFolders) lock (_ignoredFiles) { _ignoredFolders.Clear(); _ignoredFiles.Clear(); foreach (var folder in properties.IgnoredFolders) { if (!folder.EndsWith("\\")) { _ignoredFolders.Add(new Uri(_basePath, new Uri(folder + "\\", UriKind.RelativeOrAbsolute))); } else { _ignoredFolders.Add(new Uri(_basePath, new Uri(folder, UriKind.RelativeOrAbsolute))); } } foreach (var file in properties.IgnoredFiles) { _ignoredFiles.Add(new Uri(_basePath, new Uri(file, UriKind.RelativeOrAbsolute))); } } return(true); } catch (Exception) { return(false); } }
#pragma warning disable RS1012 // Start action has no registered actions. public static Settings Cache(CompilationStartAnalysisContext context) #pragma warning restore RS1012 // Start action has no registered actions. { // See docs for using AdditionalFiles: // https://github.com/dotnet/roslyn/blob/master/docs/analyzers/Using%20Additional%20Files.md // Using OrdinalIgnoreCase to compare file names per MSDN: // https://msdn.microsoft.com/en-us/library/dd465121.aspx#choosing_a_stringcomparison_member_for_your_method_call AdditionalText additionalText = context.Options?.AdditionalFiles .FirstOrDefault(file => string.Equals(Path.GetFileName(file.Path), SettingsFileName, StringComparison.OrdinalIgnoreCase)); SourceText sourceText = additionalText?.GetText(context.CancellationToken); if (sourceText == null || !context.TryGetValue(sourceText, ValueProvider, out Settings result)) { result = DefaultSettings; } return(result); }
private static void CreateAndAddStyleCopSettingsToCache(AdditionalText additionalFile, DeserializationFailureBehavior failureBehavior, CancellationToken cancellationToken, Func <SourceText, SourceTextValueProvider <StyleCopSettings>, StyleCopSettings> contextSettingsProvider) { SourceText text = GetStyleCopSettingsText(additionalFile, cancellationToken); if (text == null) { lock (settingsByFileName) { settingsByFileName.Add(additionalFile.Path, new StyleCopSettings()); } return; } if (failureBehavior == DeserializationFailureBehavior.ReturnDefaultSettings) { StyleCopSettings settings = contextSettingsProvider(text, SettingsValueProvider); if (settings == null) { lock (settingsByFileName) { settingsByFileName.Add(additionalFile.Path, new StyleCopSettings()); } return; } lock (settingsByFileName) { settingsByFileName.Add(additionalFile.Path, settings); } return; } lock (settingsByFileName) { settingsByFileName.Add(additionalFile.Path, JsonConvert.DeserializeObject <SettingsFile>(text.ToString()).Settings); } return; }
public SourceGeneratorProjectItem(string basePath, string filePath, string relativePhysicalPath, string fileKind, AdditionalText additionalText, string?cssScope, GeneratorExecutionContext context) { BasePath = basePath; FilePath = filePath; RelativePhysicalPath = relativePhysicalPath; _fileKind = fileKind; AdditionalText = additionalText; CssScope = cssScope; _context = context; var text = AdditionalText.GetText(); if (text is null) { _context.ReportDiagnostic(Diagnostic.Create(RazorDiagnostics.SourceTextNotFoundDescriptor, Location.None, filePath)); } else { RazorSourceDocument = new SourceTextRazorSourceDocument(AdditionalText.Path, relativePhysicalPath, text); } }
private static void AddSourceForAdditionalFile( GeneratorExecutionContext context, AdditionalText file ) { // We're going to "comment" out the contents of the file when generating this var sourceText = file.GetText(context.CancellationToken); Contract.ThrowIfNull(sourceText, "Failed to fetch the text of an additional file."); var changes = sourceText.Lines.SelectAsArray( l => new TextChange(new TextSpan(l.Start, length: 0), "// ") ); var generatedText = sourceText.WithChanges(changes); // TODO: remove the generatedText.ToString() when I don't have to specify the encoding context.AddSource( GetGeneratedFileName(file.Path), SourceText.From(generatedText.ToString(), encoding: Encoding.UTF8) ); }
public override void Initialize(AnalysisContext context) { context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.EnableConcurrentExecution(); context.RegisterCompilationStartAction(compilationStartContext => { // Find the additional file with the terms. ImmutableArray <AdditionalText> additionalFiles = compilationStartContext.Options.AdditionalFiles; AdditionalText termsFile = additionalFiles.FirstOrDefault(file => Path.GetFileName(file.Path).Equals("Terms.txt")); if (termsFile != null) { HashSet <string> terms = new HashSet <string>(); // Read the file line-by-line to get the terms. SourceText fileText = termsFile.GetText(compilationStartContext.CancellationToken); foreach (TextLine line in fileText.Lines) { terms.Add(line.ToString()); } // Check every named type for the invalid terms. compilationStartContext.RegisterSymbolAction(symbolAnalysisContext => { INamedTypeSymbol namedTypeSymbol = (INamedTypeSymbol)symbolAnalysisContext.Symbol; string symbolName = namedTypeSymbol.Name; foreach (string term in terms) { if (symbolName.Contains(term)) { symbolAnalysisContext.ReportDiagnostic( Diagnostic.Create(Rule, namedTypeSymbol.Locations[0], term)); } } }, SymbolKind.NamedType); } }); }
public Impl( AbstractResxGenerator generator, string language, AdditionalText resourceFile, string resourceName, string?resourceClassName, bool omitGetResourceString, bool asConstants, bool includeDefaultValues, bool emitFormatMethods) { Generator = generator; Language = language; ResourceFile = resourceFile; ResourceName = resourceName; ResourceClassName = resourceClassName; OmitGetResourceString = omitGetResourceString; AsConstants = asConstants; IncludeDefaultValues = includeDefaultValues; EmitFormatMethods = emitFormatMethods; OutputText = SourceText.From("", Encoding.UTF8); }
/// <inheritdoc /> public XElement ParseXmlFile(AdditionalText xmlFile, CancellationToken cancellationToken = default(CancellationToken)) { try { var xml = string.Empty; if (!cancellationToken.IsCancellationRequested) { xml = xmlFile.GetText(cancellationToken).ToString(); } if (!cancellationToken.IsCancellationRequested) { return(XElement.Parse(xml)); } } catch (XmlException ex) { ParsingDiagnostics.Add(Diagnostic.Create(_additionalFileParseRule, Location.None, ex.Message)); } return(null); }
/// <summary> /// This method searches for a file called checkers.xml in the project being analyzed. It must be /// identifed as an "AdditionalFiles" node in the csproj xml. /// /// The mechanism for pulling in additional files and reading the xml content was based on the sample /// provided in the roslyn source: https://github.com/dotnet/roslyn/blob/master/docs/analyzers/Using%20Additional%20Files.md /// </summary> /// <param name="additionalFiles">The additional files present in the target code</param> /// <param name="cancellationToken">The analysis cancellation token</param> /// <returns></returns> private List <string> GetCheckersFromAdditionalFiles(ImmutableArray <AdditionalText> additionalFiles, CancellationToken cancellationToken) { // The list of checkers to be returned List <string> checkers = new List <string>(); // Find the file with the checkers we are enabling AdditionalText checkersFile = additionalFiles.FirstOrDefault(file => Path.GetFileName(file.Path).Equals("checkers.xml")); if (checkersFile != null) { SourceText fileText = checkersFile.GetText(cancellationToken); MemoryStream stream = new MemoryStream(); using (StreamWriter writer = new StreamWriter(stream, System.Text.Encoding.UTF8, 1024, true)) { fileText.Write(writer); } stream.Position = 0; try { // Read all the <Checker> elements to get the checkers. XDocument document = XDocument.Load(stream); foreach (XElement termElement in document.Descendants("Checker")) { checkers.Add(termElement.Value); } } catch (Exception ex) { //If we are unable to parse the document, then we may be editing it currently. Debug.WriteLine($"Error reading the 'checkers.xml' document. Exception: {ex.Message}"); } } return(checkers); }
private static ImmutableHashSet <string> GetAllowedList( ImmutableArray <AdditionalText> additionalFiles ) { ImmutableHashSet <string> .Builder allowedClasses = ImmutableHashSet.CreateBuilder <string>(); AdditionalText allowedListFile = additionalFiles.FirstOrDefault( file => Path.GetFileName(file.Path) == AllowedListFileName ); if (allowedListFile == null) { return(allowedClasses.ToImmutableHashSet()); } SourceText allowedListText = allowedListFile.GetText(); foreach (TextLine line in allowedListText.Lines) { allowedClasses.Add(line.ToString().Trim()); } return(allowedClasses.ToImmutableHashSet()); }
private ImmutableHashSet <string> GetWhitelist( ImmutableArray <AdditionalText> additionalFiles ) { ImmutableHashSet <string> .Builder whitelistedClasses = ImmutableHashSet.CreateBuilder <string>(); AdditionalText whitelistFile = additionalFiles.FirstOrDefault( file => Path.GetFileName(file.Path) == WhitelistFileName ); if (whitelistFile == null) { return(whitelistedClasses.ToImmutableHashSet()); } SourceText whitelistText = whitelistFile.GetText(); foreach (TextLine line in whitelistText.Lines) { whitelistedClasses.Add(line.ToString().Trim()); } return(whitelistedClasses.ToImmutableHashSet()); }
private void Generate(GeneratorExecutionContext context, AdditionalText file) { //Debugger.Launch(); var hlsl = file.GetText() !.ToString(); var forbidden = hlsl.Contains("class") ? "class" : hlsl.Contains("interface") ? "interface" : null; if (forbidden is not null) { //var ind = hlsl.IndexOf(forbidden); //var forbiddenSpan = new TextSpan(ind, forbidden.Length); //var precedingLines = hlsl.AsSpan().Slice(0, ind); //var lineCount = 0; //for (var i = 0; i < precedingLines.Length; i++) //{ // if (precedingLines[i] == '\n') // { // lineCount++; // } //} //var forbiddenLineSpan = new LinePositionSpan(new LinePosition(lineCount, 0), new LinePosition(lineCount, forbidden.Length)); //context.ReportDiagnostic(Diagnostic.Create(ContainsClassesOrInterfaces, Location.Create(file.Path, forbiddenSpan, forbiddenLineSpan))); context.ReportDiagnostic(Diagnostic.Create(ContainsClassesOrInterfaces, Location.Create(file.Path, new TextSpan(0, 1), new LinePositionSpan(new LinePosition(0, 1), new LinePosition(0, 2))))); return; } if (!hlsl.Contains("struct")) { return; } var @namespace = file.Path.AsMemory().Slice(file.Path.LastIndexOf('.')); }
public bool TryReadAdditionalFilesOption(GeneratorExecutionContext context, AdditionalText additionalText, string property, out string value) { return(context.AnalyzerConfigOptions.GetOptions(additionalText).TryGetValue($"build_metadata.AdditionalFiles.{property}", out value)); }
internal static DocumentId?GetDocumentForFile(this Project project, AdditionalText additionalText) => project.GetDocumentIdWithFilePath(additionalText.Path);
public override AnalyzerConfigOptions GetOptions(AdditionalText textFile) => _treeDict.TryGetValue(textFile, out var options) ? options : DictionaryAnalyzerConfigOptions.Empty;
internal static bool IsProjectOutput(AdditionalText file) => ParameterLoader.ConfigurationFilePathMatchesExpected(file.Path, ConfigurationAdditionalFile);
public override void Initialize(AnalysisContext context) { context.RegisterCompilationStartAction(compilationContext => { AdditionalText publicApiAdditionalText = TryGetPublicApiSpec(compilationContext.Options.AdditionalFiles); if (publicApiAdditionalText == null) { return; } HashSet <string> declaredPublicSymbols = ReadPublicSymbols(publicApiAdditionalText); HashSet <string> examinedPublicTypes = new HashSet <string>(); object lockObj = new object(); compilationContext.RegisterSymbolAction(symbolContext => { var symbol = symbolContext.Symbol; var methodSymbol = symbol as IMethodSymbol; if (methodSymbol != null && ignorableMethodKinds.Contains(methodSymbol.MethodKind)) { return; } if (!IsPublicOrPublicProtected(symbol)) { return; } var publicApiName = symbol.ToDisplayString(PublicApiFormat); lock (lockObj) { examinedPublicTypes.Add(publicApiName); if (!declaredPublicSymbols.Contains(publicApiName)) { var errorMessageName = symbol.ToDisplayString(ShortSymbolNameFormat); foreach (var sourceLocation in symbol.Locations.Where(loc => loc.IsInSource)) { symbolContext.ReportDiagnostic(Diagnostic.Create(DeclareNewApiRule, sourceLocation, errorMessageName)); } } } }, SymbolKind.NamedType, SymbolKind.Event, SymbolKind.Field, SymbolKind.Method); compilationContext.RegisterCompilationEndAction(compilationEndContext => { ImmutableArray <string> deletedSymbols; lock (lockObj) { deletedSymbols = declaredPublicSymbols.Where(symbol => !examinedPublicTypes.Contains(symbol)).ToImmutableArray(); } foreach (var symbol in deletedSymbols) { var location = Location.Create(publicApiAdditionalText.Path, default(TextSpan), default(LinePositionSpan)); compilationEndContext.ReportDiagnostic(Diagnostic.Create(RemoveDeletedApiRule, location, symbol)); } }); }); }