public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node) { node = (MethodDeclarationSyntax)base.VisitMethodDeclaration(node); var attributes = node.AttributeLists.ToString(); if (attributes.Contains("[DllImport(")) { if (attributes.Contains("[DllImport(\"\"")) { return(null); } var methodName = node.Identifier.ValueText; if (this.parent.namesToNamespaces.TryGetValue(methodName, out var requiredNamespace)) { var currentNamespace = SyntaxUtils.GetEnclosingNamespace(node); if (requiredNamespace != currentNamespace) { if (!this.namespaceToMovedData.TryGetValue(requiredNamespace, out var movedData)) { movedData = new MovedData(); this.namespaceToMovedData[requiredNamespace] = movedData; } movedData.Methods.Add(node); return(null); } } } return(node); }
private void AddNode(Architecture arch, SyntaxNode node) { string name = SyntaxUtils.GetFullName(node, true); string fullSignature = GetFullSignature(node); if (!this.namesToInfos.TryGetValue(name, out var crossArchInfos)) { crossArchInfos = new List <CrossArchInfo>(); this.namesToInfos[name] = crossArchInfos; } foreach (var info in crossArchInfos) { if (info.FullSignature == fullSignature) { info.Arch |= arch; return; } } var newInfo = new CrossArchInfo() { Arch = arch, FullSignature = fullSignature }; crossArchInfos.Add(newInfo); }
public override void VisitStructDeclaration(StructDeclarationSyntax node) { if (!SyntaxUtils.IsEmptyStruct(node)) { this.foundStructs.Add(node.Identifier.ValueText); } }
public override SyntaxNode VisitParameter(ParameterSyntax node) { string fullName = SyntaxUtils.GetFullName(node); if (this.GetRemapInfo(fullName, out List <AttributeSyntax> listAttributes, node.Type.ToString(), out string newType, out string newName)) { node = (ParameterSyntax)base.VisitParameter(node); if (listAttributes != null) { foreach (var attrNode in listAttributes) { var attrListNode = SyntaxFactory.AttributeList( SyntaxFactory.SingletonSeparatedList <AttributeSyntax>(attrNode)); node = node.WithAttributeLists(node.AttributeLists.Add(attrListNode)); } } if (newName != null) { node = node.WithIdentifier(SyntaxFactory.Identifier(newName)); } if (newType != null) { node = node.WithType(SyntaxFactory.ParseTypeName(newType).WithTrailingTrivia(SyntaxFactory.Space)); // Get rid of the NativeTypeName attribute so the type we just changed to doesn't get overridden var attr = SyntaxUtils.GetAttribute(node.AttributeLists, "NativeTypeName"); if (attr != null) { node = node.RemoveNode(attr, SyntaxRemoveOptions.KeepLeadingTrivia); } } }
public void SkipAllWhitespaces() { do { char c0 = Peek(); char c1 = Peek(1); if (c0 == InvalidCharacter) { break; } else if (c0 == '\t') { AdvanceTab(); } else if (SyntaxUtils.IsLineBreak(c0)) { int nb = SyntaxUtils.GetLineBreakChars(c0, c1); AdvanceLine(nb); } else if (char.IsWhiteSpace(c0)) { AdvanceColumn(); } else { break; } } while (!IsEOF); }
public int AdvanceAuto(int numChars = 1) { // @NOTE(final): This is super slow, so only use it when needed Debug.Assert(numChars >= 1); TextPosition p = TextPosition; int result = 0; while (result < numChars) { char c0 = Peek(); char c1 = Peek(1); if (SyntaxUtils.IsLineBreak(c0)) { int lb = SyntaxUtils.GetLineBreakChars(c0, c1); p.Line++; p.Column = 1; p.Index += lb; result += lb; } if (c0 == '\t') { p.Column += ColumnsPerTab; p.Index++; result++; } else { p.Column++; p.Index++; result++; } } TextPosition = p; return(result); }
public void ShouldDocument(string uncommentedCode, string expectedCommentedCode) { // Arrange var options = new CtorDocumentationOptions { Enabled = true, Required = true, Summary = new SummaryDocumentationOptions { Template = "Creates a new instance of the {name} class." }, Parameters = new ParamsDocumentationOptions { Enabled = true, Template = "The {name}." }, Exceptions = new ExceptionDocumentationOptions { Enabled = true } }; var ctorDeclarationSyntax = SyntaxUtils.Parse <ConstructorDeclarationSyntax>(uncommentedCode); var strategy = new ConstructorDocumentationStrategy(NullLogger <ConstructorDocumentationStrategy> .Instance, new HumanizeFormatter(new DocumentationOptions()), options); // Act var documentedSyntax = strategy.Apply(ctorDeclarationSyntax); // Assert documentedSyntax.ToFullString().Trim().ShouldBe(expectedCommentedCode.Trim()); }
public void Setup() { _classDocumentationStrategy = new ClassDocumentationStrategy( NullLogger <ClassDocumentationStrategy> .Instance, new HumanizeFormatter(new DocumentationOptions()), new ClassDocumentationOptions()); _classDeclarationSyntax = SyntaxUtils.Parse <ClassDeclarationSyntax>(ClassWithInheritance); }
public override SyntaxNode VisitStructDeclaration(StructDeclarationSyntax node) { // If the struct is empty and we found a non-empty struct in all the source files, delete it if (SyntaxUtils.IsEmptyStruct(node) && this.nonEmptyStructs.Contains(node.Identifier.ValueText)) { return(null); } return(base.VisitStructDeclaration(node)); }
public static bool IsPotentialCrossArch(MethodDeclarationSyntax node) { var dllImportAttr = SyntaxUtils.GetAttribute(node.AttributeLists, "DllImport"); if (dllImportAttr != null) { return(true); } return(false); }
private static string GetNativeTypeForSignature(SyntaxList <AttributeListSyntax> attributeLists) { var nativeType = SyntaxUtils.GetNativeTypeNameFromAttributesLists(attributeLists); // If the native type has a '/' it means it contains a path, which won't compare well // in a cloud build when different architectures are built on different agents. Just // return null in that case if (nativeType != null && nativeType.Contains('/')) { nativeType = null; } return(nativeType); }
public void ShouldDocument(string uncommentedCode, string expectedCommentedCode) { // Arrange var classDeclarationSyntax = SyntaxUtils.Parse <ClassDeclarationSyntax>(uncommentedCode); var strategy = new ClassDocumentationStrategy(NullLogger <ClassDocumentationStrategy> .Instance, new HumanizeFormatter(new DocumentationOptions()), new ClassDocumentationOptions()); // Act var documentedSyntax = strategy.Apply(classDeclarationSyntax); // Assert documentedSyntax.ToFullString().ShouldBe(expectedCommentedCode); }
public void AdvanceManual(char first, char second) { if (first == '\t') { AdvanceTab(); } else if (SyntaxUtils.IsLineBreak(first)) { int nb = SyntaxUtils.GetLineBreakChars(first, second); AdvanceLine(nb); } else { AdvanceColumn(); } }
public override SyntaxNode VisitParameter(ParameterSyntax node) { string fullName = GetFullNameWithoutArchSuffix(node); if (this.GetRemapInfo(fullName, out List <AttributeSyntax> listAttributes, node.Type.ToString(), out string newType, out string newName)) { node = (ParameterSyntax)base.VisitParameter(node); if (listAttributes != null) { foreach (var attrNode in listAttributes) { var attrListNode = SyntaxFactory.AttributeList( SyntaxFactory.SingletonSeparatedList <AttributeSyntax>(attrNode)); node = node.WithAttributeLists(node.AttributeLists.Add(attrListNode)); } } if (newName != null) { node = node.WithIdentifier(SyntaxFactory.Identifier(newName)); } if (newType != null) { node = node.WithType(SyntaxFactory.ParseTypeName(newType).WithTrailingTrivia(SyntaxFactory.Space)); // Get rid of the NativeTypeName attribute so the type we just changed to doesn't get overridden var attr = SyntaxUtils.GetAttribute(node.AttributeLists, "NativeTypeName"); if (attr != null) { var attrList = (AttributeListSyntax)attr.Parent; // We want to delete the attribute, but if it's the last one in the list, // remove the list if (attrList.Attributes.Count == 1) { node = node.RemoveNode(attrList, SyntaxRemoveOptions.KeepLeadingTrivia); } // If it's not the last attribute, just remove the attribute else { node = node.RemoveNode(attr, SyntaxRemoveOptions.KeepLeadingTrivia); } } } }
private bool LexUntilCodeEnd(CommandResult commandResult) { // Special case, we dont want to parse doxygen stuff inside a code section // so we wait until a @endcode follows bool isComplete = false; while (!Buffer.IsEOF) { char c0 = Buffer.Peek(); char c1 = Buffer.Peek(1); if ((c0 == '@' || c0 == '\\') && SyntaxUtils.IsIdentStart(c1)) { Buffer.StartLexeme(); Buffer.AdvanceColumn(); Buffer.AdvanceColumnsWhile(SyntaxUtils.IsIdentPart); string ident = Buffer.GetSourceText(Buffer.LexemeStart.Index + 1, Buffer.LexemeWidth - 1); if ("endcode".Equals(ident)) { PushToken(DoxygenTokenPool.Make(DoxygenTokenKind.CommandEnd, Buffer.LexemeRange, true)); isComplete = true; break; } } else if (SyntaxUtils.IsLineBreak(c0)) { int lb = SyntaxUtils.GetLineBreakChars(c0, c1); Buffer.AdvanceLine(lb); } else if ('\t'.Equals(c0)) { Buffer.AdvanceTab(); } else { Buffer.AdvanceColumn(); } } if (!isComplete) { AddError(commandResult.StartPos, $"Unterminated code-block, expect '@endcode' or '\\endcode'", "Code", commandResult.CommandName); return(false); } return(true); }
private void AddNode(Architecture arch, SyntaxNode node) { string name = SyntaxUtils.GetFullName(node, true); string fullSignature = GetFullSignature(node); string altSignature = string.Empty; if (arch == Architecture.X86 && node is StructDeclarationSyntax structNode) { var packing4AttrList = SyntaxFactory.AttributeList( SyntaxFactory.SingletonSeparatedList <AttributeSyntax>( SyntaxFactory.Attribute( SyntaxFactory.ParseName("StructLayout"), SyntaxFactory.ParseAttributeArgumentList("(LayoutKind.Sequential, Pack = 4)")))); var tempNode = structNode.AddAttributeLists(packing4AttrList); altSignature = GetFullSignature(tempNode); } lock (this.namesToInfos) { if (!this.namesToInfos.TryGetValue(name, out var crossArchInfos)) { crossArchInfos = new List <CrossArchInfo>(); this.namesToInfos[name] = crossArchInfos; } foreach (var info in crossArchInfos) { if (info.FullSignature == fullSignature || info.FullSignature == altSignature) { info.Arch |= arch; return; } } var newInfo = new CrossArchInfo() { Arch = arch, FullSignature = fullSignature }; crossArchInfos.Add(newInfo); } }
public override SyntaxNode VisitDelegateDeclaration(DelegateDeclarationSyntax node) { string fullName = SyntaxUtils.GetFullName(node); // Remove duplicate delegates in this tree if (this.visitedDelegateNames.Contains(fullName)) { return(null); } this.visitedDelegateNames.Add(fullName); string returnFullName = $"{fullName}::return"; if (this.GetRemapInfo(returnFullName, out List <AttributeSyntax> listAttributes, node.ReturnType.ToString(), out var newType, out _)) { node = (DelegateDeclarationSyntax)base.VisitDelegateDeclaration(node); if (listAttributes != null) { foreach (var attrNode in listAttributes) { var attrListNode = SyntaxFactory.AttributeList( SyntaxFactory.SingletonSeparatedList <AttributeSyntax>(attrNode)) .WithTarget( SyntaxFactory.AttributeTargetSpecifier( SyntaxFactory.Token(SyntaxKind.ReturnKeyword))); node = node.WithAttributeLists(node.AttributeLists.Add(attrListNode)); } if (newType != null) { node = node.WithReturnType(SyntaxFactory.ParseTypeName(newType).WithTrailingTrivia(SyntaxFactory.Space)); } } return(node); } return(base.VisitDelegateDeclaration(node)); }
private SyntaxNode VisitDeclarationSyntax(MemberDeclarationSyntax node, string name) { if (this.parent.namesToNamespaces.TryGetValue(name, out var requiredNamespace)) { var currentNamespace = SyntaxUtils.GetEnclosingNamespace(node); if (requiredNamespace != currentNamespace) { if (!this.namespaceToMovedData.TryGetValue(requiredNamespace, out var movedData)) { movedData = new MovedData(); this.namespaceToMovedData[requiredNamespace] = movedData; } movedData.Others.Add(node); return(null); } } return(node); }
private LexResult LexIdent(bool isPreprocessor) { Debug.Assert(SyntaxUtils.IsIdentStart(Buffer.Peek())); StringBuilder identBuffer = new StringBuilder(); while (!Buffer.IsEOF) { char c = Buffer.Peek(); if (SyntaxUtils.IsIdentPart(c)) { identBuffer.Append(c); Buffer.AdvanceColumn(); } else { break; } } CppTokenKind kind = CppTokenKind.IdentLiteral; TextPosition identStart = Buffer.LexemeStart; int identLength = Buffer.LexemeWidth; string identString = identBuffer.ToString(); if (isPreprocessor && PreProcessorKeywords.Contains(identString)) { kind = CppTokenKind.PreprocessorKeyword; } else if (ReservedKeywords.Contains(identString)) { kind = CppTokenKind.ReservedKeyword; } else if (TypeKeywords.Contains(identString) || GlobalClassKeywords.Contains(identString)) { kind = CppTokenKind.TypeKeyword; } else { kind = CppTokenKind.IdentLiteral; } return(new LexResult(kind, true)); }
public override SyntaxNode VisitParameter(ParameterSyntax node) { string fullName = SyntaxUtils.GetFullName(node); if (this.GetRemapInfo(fullName, out List <AttributeSyntax> listAttributes, node.Type.ToString(), out string newType, out string newName)) { node = (ParameterSyntax)base.VisitParameter(node); if (listAttributes != null) { foreach (var attrNode in listAttributes) { var attrListNode = SyntaxFactory.AttributeList( SyntaxFactory.SingletonSeparatedList <AttributeSyntax>(attrNode)); node = node.WithAttributeLists(node.AttributeLists.Add(attrListNode)); } } if (newName != null) { node = node.WithIdentifier(SyntaxFactory.Identifier(newName)); } if (newType != null) { node = node.WithType(SyntaxFactory.ParseTypeName(newType).WithTrailingTrivia(SyntaxFactory.Space)); } return(node); } var ret = (ParameterSyntax)base.VisitParameter(node); // Get rid of default parameter values if (ret.Default != null) { ret = ret.WithDefault(null); } return(ret); }
public void SkipLineBreaks(SkipType type) { do { char c0 = Peek(); char c1 = Peek(1); if (c0 == InvalidCharacter) { break; } else if (SyntaxUtils.IsLineBreak(c0)) { int lb = SyntaxUtils.GetLineBreakChars(c0, c1); AdvanceLine(lb); } else { break; } } while (!IsEOF && type == SkipType.All); }
public static LexResult LexSingleLineComment(TextStream stream, bool init) { CppTokenKind kind = CppTokenKind.SingleLineComment; if (init) { Debug.Assert(stream.Peek(0) == '/'); Debug.Assert(stream.Peek(1) == '/'); stream.AdvanceColumns(2); if (DoxygenSyntax.SingleLineDocChars.Contains(stream.Peek())) { stream.AdvanceColumn(); kind = CppTokenKind.SingleLineCommentDoc; } } while (!stream.IsEOF) { char c0 = stream.Peek(); char c1 = stream.Peek(1); if (c0 == TextStream.InvalidCharacter) { break; } else if (SyntaxUtils.IsLineBreak(c0)) { break; } else if (c0 == '\t') { stream.AdvanceTab(); } else { stream.AdvanceColumn(); } } bool isComplete = stream.IsEOF || SyntaxUtils.IsLineBreak(stream.Peek()); return(new LexResult(kind, isComplete)); }
private static SyntaxList <AttributeListSyntax> FixRemappedAttributes( SyntaxList <AttributeListSyntax> existingAttrList, List <AttributeSyntax> remappedListAttributes, AttributeTargetSpecifierSyntax target) { if (remappedListAttributes == null) { return(existingAttrList); } foreach (var attrNode in remappedListAttributes) { var attrName = attrNode.Name.ToString(); if (attrName.EndsWith(EncodeHelpers.AttributeToRemoveSuffix)) { var attrNameToRemove = attrName.Substring(0, attrName.Length - EncodeHelpers.AttributeToRemoveSuffix.Length); existingAttrList = SyntaxUtils.RemoveAttribute(existingAttrList, attrNameToRemove); } else { // Remove any existing attribute with the same name existingAttrList = SyntaxUtils.RemoveAttribute(existingAttrList, attrName); var attrListNode = SyntaxFactory.AttributeList( SyntaxFactory.SingletonSeparatedList <AttributeSyntax>(attrNode)); if (target != null) { attrListNode = attrListNode.WithTarget(target); } existingAttrList = existingAttrList.Add(attrListNode); } } return(existingAttrList); }
public void SkipSpacings(SkipType type) { do { char c = Peek(); if (c == InvalidCharacter) { break; } else if (c == '\t') { AdvanceTab(); } else if (SyntaxUtils.IsSpacing(c)) { AdvanceColumn(); } else { break; } } while (!IsEOF && type == SkipType.All); }
private string GetFullNameWithArch(SyntaxNode node, Architecture arch) { return(GetUniqueNameWithArches(SyntaxUtils.GetFullName(node, true), arch)); }
private CommandResult LexCommandTokens() { Debug.Assert(DoxygenSyntax.IsCommandBegin(Buffer.Peek())); // Command Buffer.StartLexeme(); Buffer.AdvanceColumn(); DoxygenTokenKind kind = DoxygenTokenKind.Command; { char first = Buffer.Peek(); switch (first) { case '{': case '}': kind = (first == '{') ? DoxygenTokenKind.GroupStart : DoxygenTokenKind.GroupEnd; Buffer.AdvanceColumn(); break; case '$': case '@': case '\\': case '~': case '<': case '=': case '>': case '#': case '"': Buffer.AdvanceColumn(); break; case ':': case '|': case '-': Buffer.AdvanceColumnsWhile(d => d.Equals(first)); break; default: if (DoxygenSyntax.IsCommandIdentStart(first)) { while (!Buffer.IsEOF) { if (!DoxygenSyntax.IsCommandIdentPart(Buffer.Peek())) { break; } Buffer.AdvanceColumn(); } } break; } } TextPosition commandStart = Buffer.LexemeStart; int commandLen = Buffer.LexemeWidth; string commandName = Buffer.GetSourceText(Buffer.LexemeStart.Index + 1, commandLen - 1); var rule = DoxygenSyntax.GetCommandRule(commandName); if (rule != null) { if (rule.Kind == DoxygenSyntax.CommandKind.StartCommandBlock) { kind = DoxygenTokenKind.CommandStart; } else if (rule.Kind == DoxygenSyntax.CommandKind.EndCommandBlock) { kind = DoxygenTokenKind.CommandEnd; } } else { // @NOTE(final): Group start/end are not a "known" command if (kind != DoxygenTokenKind.GroupStart && kind != DoxygenTokenKind.GroupEnd) { kind = DoxygenTokenKind.InvalidCommand; } } DoxygenToken commandToken = DoxygenTokenPool.Make(kind, Buffer.LexemeRange, true); PushToken(commandToken); CommandResult result = new CommandResult(commandStart, rule, commandName); string typeName = "Command"; if (rule != null) { int argNumber = 0; int argCount = rule.Args.Count(); bool noMoreArgs = false; foreach (var arg in rule.Args) { // @TODO(final): Handle rule repeat type for arguments on same type char first = Buffer.Peek(); if (!arg.Flags.HasFlag(DoxygenSyntax.ArgumentFlags.DirectlyAfterCommand)) { if (SyntaxUtils.IsSpacing(first) || first == '\t') { Buffer.SkipSpacings(TextStream.SkipType.All); } else { // No more arguments are following noMoreArgs = true; } } Buffer.StartLexeme(); // Prefix string prefix = arg.Prefix; string postfix = arg.Postfix; bool hadPrefix = false; if (prefix != null && !noMoreArgs) { if (!string.IsNullOrEmpty(prefix)) { if (Buffer.CompareText(0, prefix) == 0) { Buffer.AdvanceColumns(prefix.Length); hadPrefix = true; } } else if ((prefix.Length == 0) && (!string.IsNullOrEmpty(postfix))) { hadPrefix = true; } } switch (arg.Kind) { case DoxygenSyntax.ArgumentKind.PrefixToPostfix: { if (hadPrefix && !noMoreArgs) { Debug.Assert(!string.IsNullOrEmpty(postfix)); bool foundPrefixToPostfix = false; while (!Buffer.IsEOF) { if (Buffer.CompareText(0, postfix) == 0) { Buffer.AdvanceColumns(postfix.Length); foundPrefixToPostfix = true; break; } else if (SyntaxUtils.IsLineBreak(Buffer.Peek())) { break; } else { Buffer.AdvanceColumn(); } } if (arg.IsOptional || foundPrefixToPostfix) { DoxygenToken argToken = DoxygenTokenPool.Make(DoxygenTokenKind.ArgumentCaption, Buffer.LexemeRange, foundPrefixToPostfix); PushToken(argToken); } else if (arg.IsRequired) { AddError(Buffer.TextPosition, $"Expected postfix '{postfix}' for argument ({argNumber}:{arg}) in command '{commandName}'", typeName, commandName); return(result); } } else if (arg.IsOptional) { DoxygenToken argToken = DoxygenTokenPool.Make(DoxygenTokenKind.ArgumentCaption, Buffer.LexemeRange, false); PushToken(argToken); } else if (arg.IsRequired) { AddError(Buffer.TextPosition, $"Expected prefix '{prefix}' for argument ({argNumber}:{arg}) in command '{commandName}'", typeName, commandName); return(result); } } break; case DoxygenSyntax.ArgumentKind.MultipleObjectReference: case DoxygenSyntax.ArgumentKind.SingleObjectReference: { // @TODO(final): ReferencedObject is not always a identifier // Here are some examples of valid referenced objects: // simple_identifier // a_function() // my::awesome::namespace::object // my::awesome::namespace::function() // my#awesome#namespace#function() // method1,method2(),class#field bool foundRef = false; if (!noMoreArgs) { bool allowMultiple = arg.Kind == DoxygenSyntax.ArgumentKind.MultipleObjectReference; bool requireIdent = true; int referenceCount = 0; while (!Buffer.IsEOF) { int oldPos = Buffer.StreamPosition; char c0 = Buffer.Peek(); char c1 = Buffer.Peek(1); if (!requireIdent) { if (c0 == ':' && c1 == ':') { Buffer.AdvanceColumns(2); requireIdent = true; continue; } else if (c0 == '#') { Buffer.AdvanceColumn(); requireIdent = true; continue; } else if (c0 == ',' && referenceCount > 0 && allowMultiple) { Buffer.AdvanceColumn(); requireIdent = true; continue; } else { // Correct termination of object-reference foundRef = true; break; } } else { if (SyntaxUtils.IsIdentStart(c0)) { requireIdent = false; while (!Buffer.IsEOF) { if (!SyntaxUtils.IsIdentPart(Buffer.Peek())) { break; } Buffer.AdvanceColumn(); } if (Buffer.Peek() == '(') { // Parse until right parent Buffer.AdvanceColumn(); bool terminatedFunc = false; while (!Buffer.IsEOF) { if (Buffer.Peek() == ')') { Buffer.AdvanceColumn(); terminatedFunc = true; break; } Buffer.AdvanceAuto(); } if (!terminatedFunc) { AddError(Buffer.TextPosition, $"Unterminated function reference for argument ({argNumber}:{arg}) in command '{commandName}'", typeName, commandName); return(result); } } ++referenceCount; continue; } else { AddError(Buffer.TextPosition, $"Requires identifier, but found '{Buffer.Peek()}' for argument ({argNumber}:{arg}) in command '{commandName}'", typeName, commandName); return(result); } } } if (Buffer.IsEOF) { // Correct termination of object-reference when stream ends (Single-line) foundRef = true; } } if (arg.IsOptional || foundRef) { DoxygenToken argToken = DoxygenTokenPool.Make(DoxygenTokenKind.ArgumentIdent, Buffer.LexemeRange, foundRef); PushToken(argToken); } else if (arg.IsRequired) { AddError(Buffer.TextPosition, $"Unexpected character '{Buffer.Peek()}' for argument ({argNumber}:{arg}) in command '{commandName}'", typeName, commandName); return(result); } } break; case DoxygenSyntax.ArgumentKind.Identifier: { bool foundIdent = false; // Special handling for @param command and ... parameter if (!noMoreArgs && "param".Equals(commandName) && (arg.Kind == DoxygenSyntax.ArgumentKind.Identifier)) { if (Buffer.Peek() == '.') { char c1 = Buffer.Peek(1); char c2 = Buffer.Peek(2); if (c1 == '.' && c2 == '.') { Buffer.AdvanceColumns(3); foundIdent = true; } } } // We dont allow parsing a ident, when any special handling was matched if (!noMoreArgs && !foundIdent && SyntaxUtils.IsIdentStart(Buffer.Peek())) { foundIdent = true; while (!Buffer.IsEOF) { if (!SyntaxUtils.IsIdentPart(Buffer.Peek())) { break; } Buffer.AdvanceColumn(); } } if (arg.IsOptional || foundIdent) { DoxygenToken argToken = DoxygenTokenPool.Make(DoxygenTokenKind.ArgumentIdent, Buffer.LexemeRange, foundIdent); PushToken(argToken); } else if (arg.IsRequired) { AddError(Buffer.TextPosition, $"Unexpected character '{Buffer.Peek()}' for argument ({argNumber}:{arg}) in command '{commandName}'", typeName, commandName); return(result); } } break; case DoxygenSyntax.ArgumentKind.HeaderFile: case DoxygenSyntax.ArgumentKind.HeaderName: { bool foundFilename = false; if (!noMoreArgs) { bool requiredQuotes = arg.Kind == DoxygenSyntax.ArgumentKind.HeaderName; char curChar = Buffer.Peek(); if (curChar == '<' || curChar == '\"') { char quoteChar = curChar == '<' ? '>' : '\"'; Buffer.AdvanceColumn(); while (!Buffer.IsEOF) { curChar = Buffer.Peek(); if (curChar == quoteChar) { Buffer.AdvanceColumn(); foundFilename = true; break; } else if (SyntaxUtils.IsLineBreak(curChar)) { break; } Buffer.AdvanceColumn(); } if (!foundFilename) { AddError(Buffer.TextPosition, $"Unterminated filename, expect quote char '{quoteChar}' but got '{Buffer.Peek()}' for argument ({argNumber}:{arg}) in command '{commandName}'", typeName, commandName); return(result); } } else if (!requiredQuotes) { if (SyntaxUtils.IsFilename(Buffer.Peek())) { foundFilename = true; while (!Buffer.IsEOF) { if (!SyntaxUtils.IsFilename(Buffer.Peek())) { break; } Buffer.AdvanceColumn(); } } } } if (arg.IsOptional || foundFilename) { DoxygenToken argToken = DoxygenTokenPool.Make(DoxygenTokenKind.ArgumentFile, Buffer.LexemeRange, foundFilename); PushToken(argToken); } else if (arg.IsRequired) { AddError(Buffer.TextPosition, $"Unexpected character '{Buffer.Peek()}' for argument ({argNumber}:{arg}) in command '{commandName}'", typeName, commandName); return(result); } } break; case DoxygenSyntax.ArgumentKind.SingleWord: { // @TODO(final): IsWordStart() bool foundWord = false; if (!noMoreArgs && char.IsLetterOrDigit(Buffer.Peek())) { foundWord = true; while (!Buffer.IsEOF) { // @TODO(final): IsWordPart() if (char.IsWhiteSpace(Buffer.Peek())) { break; } Buffer.AdvanceColumn(); } } if (arg.IsOptional || foundWord) { DoxygenToken argToken = DoxygenTokenPool.Make(DoxygenTokenKind.ArgumentCaption, Buffer.LexemeRange, foundWord); PushToken(argToken); } else if (arg.IsRequired) { AddError(Buffer.TextPosition, $"Unexpected character '{Buffer.Peek()}' for argument ({argNumber}:{arg}) in command '{commandName}'", typeName, commandName); return(result); } } break; case DoxygenSyntax.ArgumentKind.QuotedString: { bool isComplete = false; // @TODO(final): Make quotes configurable in the argument rule bool hasQuote = Buffer.Peek() == '"' || Buffer.Peek() == '<'; char endQuote = char.MaxValue; if (hasQuote && !noMoreArgs) { endQuote = Buffer.Peek() == '<' ? '>' : '"'; Buffer.AdvanceColumn(); while (!Buffer.IsEOF) { if (!hasQuote) { if (char.IsWhiteSpace(Buffer.Peek())) { break; } } else { if (Buffer.Peek() == endQuote) { Buffer.AdvanceColumn(); isComplete = true; break; } else if (SyntaxUtils.IsLineBreak(Buffer.Peek()) || Buffer.Peek() == TextStream.InvalidCharacter) { break; } } Buffer.AdvanceColumn(); } if (!isComplete) { AddError(Buffer.TextPosition, $"Unterminated quote string for argument ({argNumber}:{arg}) in command '{commandName}'", typeName, commandName); return(result); } } if (arg.IsOptional || isComplete) { DoxygenToken argToken = DoxygenTokenPool.Make(DoxygenTokenKind.ArgumentText, Buffer.LexemeRange, isComplete); PushToken(argToken); } else if (arg.IsRequired) { AddError(Buffer.TextPosition, $"Unexpected character '{Buffer.Peek()}' for argument ({argNumber}:{arg}) in command '{commandName}'", typeName, commandName); return(result); } } break; case DoxygenSyntax.ArgumentKind.UntilEndOfLine: { bool eolFound = false; if (!noMoreArgs) { while (!Buffer.IsEOF) { if (SyntaxUtils.IsLineBreak(Buffer.Peek())) { eolFound = true; break; } Buffer.AdvanceColumn(); } if (Buffer.IsEOF) { eolFound = true; } } if (arg.IsOptional || eolFound) { DoxygenToken argToken = DoxygenTokenPool.Make(DoxygenTokenKind.ArgumentText, Buffer.LexemeRange, true); PushToken(argToken); } else if (arg.IsRequired) { AddError(Buffer.TextPosition, $"Unterminated end-of-line for argument ({argNumber}:{arg}) in command '{commandName}'", typeName, commandName); return(result); } } break; case DoxygenSyntax.ArgumentKind.ComplexLine: case DoxygenSyntax.ArgumentKind.ComplexBlock: // @TODO(final): Implement complex line/block properly goto CommandDone; default: AddError(Buffer.TextPosition, $"Unsupported argument ({argNumber}:{arg}) in command '{commandName}'", typeName, commandName); return(result); } // Postfix if (!noMoreArgs && (hadPrefix && !string.IsNullOrWhiteSpace(postfix) && arg.Kind != DoxygenSyntax.ArgumentKind.PrefixToPostfix)) { if (Buffer.CompareText(0, postfix) == 0) { Buffer.AdvanceColumns(prefix.Length); } else { AddError(Buffer.TextPosition, $"Expected postfix '{postfix}' for pp-argument({argNumber}:{arg}) in command '{commandName}'", typeName, commandName); return(result); } } ++argNumber; } } CommandDone: result.IsValid = true; return(result); }
public IEnumerable <Architecture> GetSignatureArchGroupings(SyntaxNode node) { string name = SyntaxUtils.GetFullName(node, true); return(this.GetSignatureArchGroupings(name)); }
public static bool IsPotentialCrossArch(StructDeclarationSyntax node) { return(node.Parent is NamespaceDeclarationSyntax && !SyntaxUtils.IsEmptyStruct(node)); }
public override SyntaxNode VisitFieldDeclaration(FieldDeclarationSyntax node) { string fullName = SyntaxUtils.GetFullName(node); this.GetRemapInfo(fullName, out var listAttributes, node.Declaration.Type.ToString(), out string newType, out string newName); // ClangSharp mistakenly emits string[] for WCHAR[] Foo = "Bar". // Change it to string if (newType == null && node.Declaration.Type.ToString() == "string[]") { newType = "string"; } // Turn public static readonly Guids into string constants with an attribute // to signal language projections to turn them into Guid constants. Guid constants // aren't allowed in metadata, requiring us to surface them this way if (node.Modifiers.ToString() == "public static readonly" && node.Declaration.Type.ToString() == "Guid") { Guid guidVal = Guid.Empty; var varInitializer = node.Declaration.Variables.First().Initializer; if (varInitializer.Value is ObjectCreationExpressionSyntax objCreationSyntax) { var args = objCreationSyntax.ArgumentList.Arguments; if (args.Count == 11) { uint p0 = EncodeHelpers.ParseHex(args[0].ToString()); ushort p1 = (ushort)EncodeHelpers.ParseHex(args[1].ToString()); ushort p2 = (ushort)EncodeHelpers.ParseHex(args[2].ToString()); byte p3 = (byte)EncodeHelpers.ParseHex(args[3].ToString()); byte p4 = (byte)EncodeHelpers.ParseHex(args[4].ToString()); byte p5 = (byte)EncodeHelpers.ParseHex(args[5].ToString()); byte p6 = (byte)EncodeHelpers.ParseHex(args[6].ToString()); byte p7 = (byte)EncodeHelpers.ParseHex(args[7].ToString()); byte p8 = (byte)EncodeHelpers.ParseHex(args[8].ToString()); byte p9 = (byte)EncodeHelpers.ParseHex(args[9].ToString()); byte p10 = (byte)EncodeHelpers.ParseHex(args[10].ToString()); guidVal = new Guid(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); } else if (objCreationSyntax.ArgumentList.Arguments.Count == 1) { // If this is an invalid format, remove the node if (!Guid.TryParse(objCreationSyntax.ArgumentList.Arguments[0].ToString(), out guidVal)) { return(null); } } } if (guidVal == Guid.Empty) { return(node); } node = node.RemoveNode(varInitializer, SyntaxRemoveOptions.KeepExteriorTrivia | SyntaxRemoveOptions.KeepEndOfLine); node = node.AddAttributeLists(EncodeHelpers.ConvertGuidToAttributeList(guidVal).WithLeadingTrivia(node.GetLeadingTrivia())); return(node); } node = (FieldDeclarationSyntax)base.VisitFieldDeclaration(node); if (listAttributes != null) { foreach (var attrNode in listAttributes) { var attrListNode = SyntaxFactory.AttributeList( SyntaxFactory.SingletonSeparatedList <AttributeSyntax>(attrNode)); node = node.WithAttributeLists(node.AttributeLists.Add(attrListNode)); } } var firstVar = node.Declaration.Variables.First(); if (newName != null) { var newVar = SyntaxFactory.VariableDeclarator(SyntaxFactory.Identifier(newName)); node = node.ReplaceNode(firstVar, newVar); } if (newType != null) { node = node.WithDeclaration(node.Declaration.WithType(SyntaxFactory.ParseTypeName(newType).WithTrailingTrivia(SyntaxFactory.Space))); } return(node); }
public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node) { // Skip methods where we weren't given a import lib name. Should we warn the caller? if (node.AttributeLists.ToString().Contains("[DllImport(\"\"")) { return(null); } string fullName = SyntaxUtils.GetFullName(node); // Remove duplicate static methods if (node.Body == null) { // If this function is supposed to be in a certain namespace, remove it if it's not. // We only respect this for static methods if (this.requiredNamespaces.TryGetValue(fullName, out var requiredNamespace)) { var ns = GetEnclosingNamespace(node); if (ns != requiredNamespace) { return(null); } } // Remove duplicate methods in this tree if (this.visitedStaticMethodNames.Contains(fullName)) { return(null); } this.visitedStaticMethodNames.Add(fullName); } // Any method with a body has to be part of a call to a vtable for an interface. // If it's not, get rid of it else if (!node.Body.ToString().Contains("GetDelegateForFunctionPointer")) { return(null); } string returnFullName = $"{fullName}::return"; // Find remap info for the return parameter for this method and apply any that we find if (this.GetRemapInfo(returnFullName, out List <AttributeSyntax> listAttributes, node.ReturnType.ToString(), out var newType, out _)) { node = (MethodDeclarationSyntax)base.VisitMethodDeclaration(node); if (listAttributes != null) { foreach (var attrNode in listAttributes) { var attrListNode = SyntaxFactory.AttributeList( SyntaxFactory.SingletonSeparatedList <AttributeSyntax>(attrNode)) .WithTarget( SyntaxFactory.AttributeTargetSpecifier( SyntaxFactory.Token(SyntaxKind.ReturnKeyword))); node = node.WithAttributeLists(node.AttributeLists.Add(attrListNode)); } } if (newType != null) { node = node.WithReturnType(SyntaxFactory.ParseTypeName(newType).WithTrailingTrivia(SyntaxFactory.Space)); } return(node); } return(base.VisitMethodDeclaration(node)); }