@ 261105.1

261102.2 · f6f7732e86d14c852739b964f23db7ed3fff82c3

updated astyle version to 3.6.21

reading declarations

Changes to src/core/. All files

src/core/astyle/ASBeautifier.cpp

@@ -102,7 +102,7 @@ ASBeautifier::ASBeautifier(const ASBeautifier& other) : ASBase(other)  	blockStatementStack = std::make_unique<std::vector<bool>>(*other.blockStatementStack); 	blockConditionalStack = std::make_unique<std::vector<bool>>(*other.blockConditionalStack);-	blockQuestionStack = std::make_unique<std::vector<bool>>(*other.blockQuestionStack);+	blockQuestionStack = std::make_unique<std::vector<int>>(*other.blockQuestionStack);  	parenStatementStack = std::make_unique<std::vector<bool>>(*other.parenStatementStack); @@ -169,7 +169,7 @@ ASBeautifier::ASBeautifier(const ASBeautifier& other) : ASBase(other) 	isInPreprocessorComment = other.isInPreprocessorComment; 	isInRunInComment = other.isInRunInComment; 	isInCase = other.isInCase;-	isInQuestion = other.isInQuestion;+	questionMarkCount = other.questionMarkCount; 	isContinuation = other.isContinuation; 	isInHeader = other.isInHeader; 	isInTemplate = other.isInTemplate;@@ -192,6 +192,7 @@ ASBeautifier::ASBeautifier(const ASBeautifier& other) : ASBase(other) 	isInEnum = other.isInEnum; 	isInEnumTypeID = other.isInEnumTypeID; 	isInStruct = other.isInStruct;+	isInDesignatedInit = other.isInDesignatedInit; 	isInLet = other.isInLet; 	isInTrailingReturnType = other.isInTrailingReturnType; 	isInConstevalCondition = other.isInConstevalCondition;@@ -326,7 +327,7 @@ void ASBeautifier::init(ASSourceIterator* iter) 	parenBlockStateStack = std::make_unique<std::vector<ParenBlockState>>(); 	blockStatementStack = std::make_unique<std::vector<bool>>(); 	blockConditionalStack = std::make_unique<std::vector<bool>>();-	blockQuestionStack = std::make_unique<std::vector<bool>>();+	blockQuestionStack = std::make_unique<std::vector<int>>(); 	parenStatementStack = std::make_unique<std::vector<bool>>(); 	braceBlockStateStack = std::make_unique<std::vector<bool>>(); 	// do not use emplace_back on std::vector<bool> until supported by macOS@@ -356,7 +357,7 @@ void ASBeautifier::init(ASSourceIterator* iter) 	isInRunInComment = false; 	isContinuation = false; 	isInCase = false;-	isInQuestion = false;+	questionMarkCount = 0; 	isIndentModeOff = false; 	isInClassHeader = false; 	isInClassHeaderTab = false;@@ -372,6 +373,7 @@ void ASBeautifier::init(ASSourceIterator* iter) 	isInEnum = false; 	isInEnumTypeID = false; 	isInStruct = false;+	isInDesignatedInit = false; 	isInLet = false; 	isInHeader = false; 	isInTemplate = false;@@ -683,7 +685,7 @@ std::string ASBeautifier::beautify(const std::string& originalLine) 					preprocBlockIndent += 1; 					isInIndentablePreprocBlock = true; 				}-				else if (preproc == "else" || preproc == "elif")+				else if (preproc == "else" || preproc.compare(0, 4, "elif") == 0) // #elif, #elifdef, #elifndef 				{ 					indentedLine = preLineWS(preprocBlockIndent - 1, 0) + line; 				}@@ -720,7 +722,7 @@ std::string ASBeautifier::beautify(const std::string& originalLine) 					                         preprocIndentStack->back().second) + line; 					return indentedLine; 				}-				if (preproc == "else" || preproc == "elif")+				if (preproc == "else" || preproc.compare(0, 4, "elif") == 0) // #elif, #elifdef, #elifndef 				{ 					if (!preprocIndentStack->empty())	// if no entry don't indent 					{@@ -1784,7 +1786,8 @@ std::unique_ptr<std::vector<std::unique_ptr<std::vector<const std::string*>>>> A }  /**- * Determine if an assignment statement ends with a comma+ * Determine if an assignment statement (index at '=') or a+ *     method call (index at '.') ends with a comma  *     that is not in a function argument. It ends with a  *     comma if a comma is the last char on the line.  *@@ -1792,7 +1795,7 @@ std::unique_ptr<std::vector<std::unique_ptr<std::vector<const std::string*>>>> A  */ bool ASBeautifier::statementEndsWithComma(std::string_view line, int index) const {-	assert(line[index] == '=');+	assert(line[index] == '=' || line[index] == '.');  	bool isInComment_ = false; 	bool isInQuote_ = false;@@ -1867,6 +1870,32 @@ bool ASBeautifier::statementEndsWithComma(std::string_view line, int index) cons 	return true; } +/**+ * Determine if the assignment at index is a designated initializer+ *     like '.member = value' that begins the line.+ *+ * @return  true if it is a designated initializer, otherwise false.+ */+bool ASBeautifier::isDesignatedInitializer(std::string_view line, size_t index) const+{+	assert(line[index] == '=');++	size_t dotPos = line.find_first_not_of(" \t");+	if (dotPos == std::string::npos || dotPos >= index || line[dotPos] != '.')+		return false;++	size_t nameStart = dotPos + 1;+	if (nameStart >= index || !isLegalNameChar(line[nameStart]) || isDigit(line[nameStart]))+		return false;++	size_t nameEnd = nameStart;+	while (nameEnd < index && isLegalNameChar(line[nameEnd]))+		++nameEnd;++	size_t nextChar = line.find_first_not_of(" \t", nameEnd);+	return nextChar == index;+}+ /**  * check if current comment is a line-end comment  *@@ -1939,6 +1968,17 @@ int ASBeautifier::getContinuationIndentComma(std::string_view line, size_t currP 			break; 	} +	// the first word must be followed by a type continuation (declaration),+	// not by an expression like a method call 'a.get(),' or 'values[0],'+	char afterFirstWord = line[indent];+	if (!std::isblank(static_cast<unsigned char>(afterFirstWord))+	        && afterFirstWord != '*'+	        && afterFirstWord != '&'+	        && afterFirstWord != ':'+	        && afterFirstWord != '<'+	        && !(afterFirstWord == '[' && peekNextChar(line, indent) == ']'))+		return 0;+ 	indent++; 	if (indent >= currPos || indent < 4) 		return 0;@@ -2150,7 +2190,7 @@ void ASBeautifier::processPreprocessor(std::string_view preproc, std::string_vie 			waitingBeautifierStack->pop_back(); 		} 	}-	else if (preproc == "elif")+	else if (preproc.compare(0, 4, "elif") == 0) // #elif, #elifdef, #elifndef 	{ 		if ((waitingBeautifierStack != nullptr) && !waitingBeautifierStack->empty()) 		{@@ -3211,9 +3251,11 @@ bool ASBeautifier::handleColonSection(std::string_view line, size_t* i, bool tab 		++*i; 		return false; 	}-	else if (isInQuestion)		// NOLINT+	else if (questionMarkCount > 0)		// NOLINT 	{-		// do nothing special+		// the ':' of a ?: sequence, do nothing special+		// #609 consume the '?' so it is not restored after a following block+		--questionMarkCount; 	} 	else if (parenDepth > 0) 	{@@ -3318,7 +3360,7 @@ bool ASBeautifier::handleColonSection(std::string_view line, size_t* i, bool tab  void ASBeautifier::handleEndOfStatement(size_t i, bool *closingBraceReached, char* ch) {-	bool isInQuestionAfterBlock = false;	// a block like a lambda body does not end a ?: sequence+	int questionMarkCountAfterBlock = 0;	// a block like a lambda body does not end a ?: sequence 	isInAssignment = isInInitializerList = false; 	quoteContinuationIndent = 0; 	if (*ch == '}')@@ -3403,7 +3445,7 @@ void ASBeautifier::handleEndOfStatement(size_t i, bool *closingBraceReached, cha 			} 			if (!blockQuestionStack->empty()) 			{-				isInQuestionAfterBlock = blockQuestionStack->back();+				questionMarkCountAfterBlock = blockQuestionStack->back(); 				blockQuestionStack->pop_back(); 			} @@ -3502,7 +3544,7 @@ void ASBeautifier::handleEndOfStatement(size_t i, bool *closingBraceReached, cha 	isInEnum = false; 	isInEnumTypeID = false; -	isInQuestion = isInQuestionAfterBlock;+	questionMarkCount = questionMarkCountAfterBlock; 	isInTemplate = false; 	isInObjCInterface = false; 	foundPreCommandHeader = false;@@ -3869,7 +3911,7 @@ void ASBeautifier::handleClosingParen(std::string_view line, size_t i, bool tabI 	// do not use emplace_back on vector<bool> until supported by macOS 	blockStatementStack->push_back(isContinuation); 	blockConditionalStack->push_back(isInConditional);-	blockQuestionStack->push_back(isInQuestion);+	blockQuestionStack->push_back(questionMarkCount); 	isInConditional = false;  	if (!continuationIndentStack->empty())@@ -3907,7 +3949,7 @@ void ASBeautifier::handleClosingParen(std::string_view line, size_t i, bool tabI 	isInClassInitializer = false; 	isInEnumTypeID = false; 	isContinuation = false;-	isInQuestion = false;+	questionMarkCount = 0; 	isInLet = false; 	foundPreCommandHeader = false; 	foundPreCommandMacro = false;@@ -4107,7 +4149,9 @@ void ASBeautifier::handlePotentialOperatorSection(std::string_view line, size_t* 		        && !lineStartsWithDot 		        && ( (foundNonAssignmentOp == &ASResource::AS_GR_GR && countLS < 2 ) 		             ||  foundNonAssignmentOp == &ASResource::AS_LS_LS-		             || (foundNonAssignmentOp == &ASResource::AS_DOT && openParenPos == methodNameEndPos && closeParenPos != std::string::npos )))+		             || (foundNonAssignmentOp == &ASResource::AS_DOT && openParenPos == methodNameEndPos && closeParenPos != std::string::npos+		                 // SF #593: a method call ending with a comma (e.g. an initializer list element) is not continued+		                 && !statementEndsWithComma(line, *i) ))) 		{ 			// this will be true if the line begins with the operator 			if (*i < foundNonAssignmentOp->length() && spaceIndentCount == 0)@@ -4128,7 +4172,12 @@ void ASBeautifier::handlePotentialOperatorSection(std::string_view line, size_t* 		if (foundAssignmentOp->length() > 1) 			*i += foundAssignmentOp->length() - 1; -		if (!isInOperator && !isInTemplate && (!isInNonInStatementArray() || isInEnum || isInStruct))+		// SF #593: a designated initializer '.member = value' within a brace array+		bool isDesignatedInit = foundAssignmentOp == &ASResource::AS_ASSIGN+		                        && isInNonInStatementArray()+		                        && isDesignatedInitializer(line, *i);++		if (!isInOperator && !isInTemplate && (!isInNonInStatementArray() || isInEnum || isInStruct || isDesignatedInit)) 		{ 			// if multiple assignments, align on the previous word 			if (foundAssignmentOp == &ASResource::AS_ASSIGN@@ -4136,7 +4185,8 @@ void ASBeautifier::handlePotentialOperatorSection(std::string_view line, size_t* 			        && statementEndsWithComma(line, *i)) 			{ 				// only one assignment indent per line + GH #10-				if (!*haveAssignmentThisLine && line.find(ASResource::AS_SCOPE_RESOLUTION) == std::string::npos)+				// a designated initializer ending with a comma needs no indent+				if (!*haveAssignmentThisLine && !isDesignatedInit && line.find(ASResource::AS_SCOPE_RESOLUTION) == std::string::npos) 				{ 					// register indent at previous word 					*haveAssignmentThisLine = true;@@ -4162,6 +4212,8 @@ void ASBeautifier::handlePotentialOperatorSection(std::string_view line, size_t*  				registerContinuationIndent(line, *i, spaceIndentCount, tabIncrementIn, 0, false); 				isContinuation = true;+				if (isDesignatedInit)+					isInDesignatedInit = true; 			} 		} 	}@@ -4551,7 +4603,7 @@ void ASBeautifier::parseCurrentLine(std::string_view line) 		}   // isPotentialHeader  		if (ch == '?')-			isInQuestion = true;+			++questionMarkCount;  		// special handling of colons XXX 533 		if (ch == ':')@@ -4568,6 +4620,13 @@ void ASBeautifier::parseCurrentLine(std::string_view line) 		} 		else if (ch == ',' && (isInEnum || isInStruct) && isNonInStatementArray && !continuationIndentStack->empty()) 			continuationIndentStack->pop_back();+		// SF #593: end of a continued designated initializer+		else if (ch == ',' && isInDesignatedInit && parenDepth == 0)+		{+			if (!continuationIndentStack->empty())+				continuationIndentStack->pop_back();+			isInDesignatedInit = false;+		}  		// handle commas 		// previous "isInStatement" will be from an assignment operator or class initializer

src/core/astyle/ASFormatter.cpp

@@ -65,6 +65,7 @@ ASFormatter::ASFormatter()     shouldBreakOneLineStatements = true;     shouldConvertTabs = false;     shouldIndentCol1Comments = false;+    shouldEndWithSingleNewline = false;     shouldIndentPreprocBlock = false;     shouldCloseTemplates = false;     shouldAttachExternC = false;@@ -198,6 +199,7 @@ void ASFormatter::init(ASSourceIterator* si)     templateDepth = 0;     squareBracketCount = 0;     parenthesesCount = 0;+    addedBraceStatementParenDepth = 0;     bracesNestingLevel = 0;     bracesNestingLevelOfStruct = 0;     squeezeEmptyLineCount = 0;@@ -300,6 +302,7 @@ void ASFormatter::init(ASSourceIterator* si)     isInObjCSelector = false;     breakCurrentOneLineBlock = false;     shouldRemoveNextClosingBrace = false;+    shouldAddClosingBraceAtStatementEnd = false;     isInBraceRunIn = false;     returnTypeChecked = false;     currentLineBeginsWithBrace = false;@@ -310,6 +313,7 @@ void ASFormatter::init(ASSourceIterator* si)     prependEmptyLine = false;     isPreviousReadyLinePreprocCondStart = false;     appendOpeningBrace = false;+    appendClosingBrace = false;     foundClosingHeader = false;     isImmediatelyPostHeader = false;     isInHeader = false;@@ -1762,6 +1766,7 @@ std::string ASFormatter::nextLine()      while (!isLineReady)     {+        const bool isReparsingCurrentChar = shouldReparseCurrentChar;         if (shouldReparseCurrentChar)             shouldReparseCurrentChar = false;         else if (!getNextChar())@@ -1908,6 +1913,28 @@ std::string ASFormatter::nextLine()                 continue;         } +        // add the closing brace deferred by addBracesToStatement() to a multi-line statement+        if (shouldAddClosingBraceAtStatementEnd && !isReparsingCurrentChar)+        {+            if (currentChar == '(' || currentChar == '[')+                ++addedBraceStatementParenDepth;+            else if (currentChar == ')' || currentChar == ']')+                --addedBraceStatementParenDepth;+            else if (currentChar == ';' && addedBraceStatementParenDepth <= 0)+            {+                // keep a line end comment with the statement+                if (isBeforeAnyLineEndComment(charNum) && sourceIterator->hasMoreLines())+                    appendClosingBrace = true;    // append brace as the following line+                else+                {+                    currentLine.insert(charNum + 1, " }");+                    assert(computeChecksumIn("}"));+                }+                shouldAddClosingBraceAtStatementEnd = false;+                addedBraceStatementParenDepth = 0;+            }+        }+         // handle white space - needed to simplify the rest.         if (std::isblank(currentChar))         {@@ -3007,6 +3034,16 @@ void ASFormatter::setLineEndFormat(LineEndFormat fmt)     lineEnd = fmt; } +/**+ * set option to end the output with exactly one line end.+ *+ * @param state        true = enforce, false = keep the input file end.+ */+void ASFormatter::setEOFNewlineMode(bool state)+{+    shouldEndWithSingleNewline = state;+}+ /**  * set option to break unrelated blocks of code with empty lines.  *@@ -3278,6 +3315,12 @@ bool ASFormatter::getNextLine(bool emptyLineWasDeleted /*false*/)     }     if (appendOpeningBrace)         currentLine = "{";		// append brace that was removed from the previous line+    else if (appendClosingBrace)+    {+        currentLine = "}";		// append brace added to the previous multi-line statement+        appendClosingBrace = false;+        assert(computeChecksumIn(currentLine));+    }     else     {         currentLine = sourceIterator->nextLine(emptyLineWasDeleted);@@ -7117,6 +7160,11 @@ LineEndFormat ASFormatter::getLineEndFormat() const     return lineEnd; } +bool ASFormatter::getEOFNewlineMode() const+{+    return shouldEndWithSingleNewline;+}+ /**  * get the current line comment adjustment that results from attaching  * a closing header to a closing brace.@@ -7285,10 +7333,16 @@ bool ASFormatter::addBracesToStatement()         if (currentChar != ';')             nextSemiColon = findNextChar(currentLine, ';', charNum + 1);         if (nextSemiColon == std::string::npos)-            return false;-+        {+            // a statement continued on the following lines gets the closing brace+            // when its terminating semi-colon is reached (not for one-line braces)+            if (shouldAddOneLineBraces || !isMultiLineStatementEndFound())+                return false;+            shouldAddClosingBraceAtStatementEnd = true;+            addedBraceStatementParenDepth = 0;+        }         // add closing brace before changing the line length-        if (nextSemiColon == currentLine.length() - 1)+        else if (nextSemiColon == currentLine.length() - 1)             currentLine.append(" }");         else             currentLine.insert(nextSemiColon + 1, " }");@@ -7296,7 +7350,7 @@ bool ASFormatter::addBracesToStatement()      // add opening brace     currentLine.insert(charNum, "{ ");-    assert(computeChecksumIn("{}"));+    assert(computeChecksumIn(shouldAddClosingBraceAtStatementEnd ? "{" : "{}"));     currentChar = '{';     if ((int) currentLine.find_first_not_of(" \t") == charNum)         currentLineBeginsWithBrace = true;@@ -7310,6 +7364,101 @@ bool ASFormatter::addBracesToStatement()     return true; } +/**+ * Check if a statement starting at charNum of the currentLine and continued+ * on the following lines is terminated by a semi-colon that is not within+ * parens or square brackets.+ * The statement must not contain braces or preprocessor directives.+ * Comments and quotes are skipped.+ *+ * @return true if the terminating semi-colon was found.+ */+bool ASFormatter::isMultiLineStatementEndFound() const+{+    constexpr int maxLinesToCheck = 100;+    int parenDepth = 0;+    int linesChecked = 0;+    bool isInComment_ = false;+    bool isFirstLine = true;+    std::string line = currentLine;++    ASPeekStream stream(sourceIterator);+    while (isFirstLine || stream.hasMoreLines())+    {+        size_t i = 0;+        if (isFirstLine)+        {+            isFirstLine = false;+            i = charNum;+        }+        else+        {+            if (++linesChecked > maxLinesToCheck)+                return false;+            line = stream.peekNextLine();+            size_t firstChar = line.find_first_not_of(" \t");+            if (firstChar == std::string::npos)+                continue;+            if (!isInComment_ && line[firstChar] == '#')+                return false;+        }++        for (; i < line.length(); i++)+        {+            if (isInComment_)+            {+                size_t endComment = line.find("*/", i);+                if (endComment == std::string::npos)+                    break;+                isInComment_ = false;+                i = endComment + 1;+                continue;+            }+            if (line.compare(i, 2, "//") == 0)+                break;+            if (line.compare(i, 2, "/*") == 0)+            {+                isInComment_ = true;+                ++i;+                continue;+            }+            const char ch = line[i];+            if (ch == '"' || (ch == '\'' && !isDigitSeparator(line, i)))+            {+                // don't try to parse raw, verbatim or text block strings+                if (ch == '"'+                        && ((i > 0 && (line[i - 1] == 'R' || line[i - 1] == '@'))+                            || line.compare(i, 3, "\"\"\"") == 0))+                    return false;+                // find the end of the quote, it must be on the same line+                size_t j = i + 1;+                while (j < line.length() && line[j] != ch)+                {+                    if (line[j] == '\\')+                        ++j;+                    ++j;+                }+                if (j >= line.length())+                    return false;+                i = j;+                continue;+            }+            if (ch == '{' || ch == '}')+                return false;+            if (ch == '(' || ch == '[')+                ++parenDepth;+            else if (ch == ')' || ch == ']')+            {+                if (--parenDepth < 0)+                    return false;+            }+            else if (ch == ';' && parenDepth == 0)+                return true;+        }+    }+    return false;+}+ /**  * Remove braces from a single line statement following a header.  * braces are not removed if the proper conditions are not met.@@ -7451,6 +7600,44 @@ size_t ASFormatter::findNextChar(std::string_view line, char searchChar, int sea     return i; } +/**+ * Check if the text in line between start and end consists only of+ * function specifiers or modifiers (e.g. "explicit", "virtual", "public").+ * In this case there is no return type, e.g. for constructors, destructors+ * and conversion operators, and the line must not be broken.+ * https://sourceforge.net/p/astyle/bugs/499/+ */+bool ASFormatter::isOnlyFunctionSpecifiers(const std::string& line, size_t start, size_t end) const+{+    static const std::string_view specifiers[] =+    {+        "explicit", "virtual", "inline", "constexpr", "consteval",+        "static", "public", "protected", "private", "internal"+    };++    if (start >= end || end > line.length())+        return false;++    for (size_t i = start; i < end; )+    {+        if (std::isblank(line[i]))+        {+            ++i;+            continue;+        }+        size_t wordEnd = i;+        while (wordEnd < end && isLegalNameChar(line[wordEnd]))+            ++wordEnd;+        if (wordEnd == i)+            return false;+        const std::string_view word(line.data() + i, wordEnd - i);+        if (std::find(std::begin(specifiers), std::end(specifiers), word) == std::end(specifiers))+            return false;+        i = wordEnd;+    }+    return true;+}+ /**  * Find split point for break/attach return type.  */@@ -7466,6 +7653,7 @@ void ASFormatter::findReturnTypeSplitPoint(const std::string& firstLine)     bool isInQuote_      = false;     bool foundSplitPoint = false;     bool isAlreadyBroken = false;+    bool hasReturnType   = true;     char quoteChar_      = ' ';     char currNonWSChar   = ' ';     char prevNonWSChar   = ' ';@@ -7625,6 +7813,7 @@ void ASFormatter::findReturnTypeSplitPoint(const std::string& firstLine)                     {                         if (breakCharNum == firstCharNum)                             isAlreadyBroken = true;+                        hasReturnType = !isOnlyFunctionSpecifiers(line, firstCharNum, breakCharNum);                         foundSplitPoint = true;                         // find the operator, may be parens                         size_t parenNum =@@ -7653,6 +7842,7 @@ void ASFormatter::findReturnTypeSplitPoint(const std::string& firstLine)                         i = nextCharNum;                         if (breakCharNum == firstCharNum)                             isAlreadyBroken = true;+                        hasReturnType = !isOnlyFunctionSpecifiers(line, firstCharNum, breakCharNum);                         foundSplitPoint = true;                         // find the operator, may be parens                         size_t parenNum =@@ -7675,6 +7865,7 @@ void ASFormatter::findReturnTypeSplitPoint(const std::string& firstLine)                     // is line is already broken?                     if (breakCharNum == firstCharNum && breakLineNum > 0)                         isAlreadyBroken = true;+                    hasReturnType = !isOnlyFunctionSpecifiers(line, firstCharNum, breakCharNum);                     ++parenCount;                     foundSplitPoint = true;                     continue;@@ -7697,7 +7888,7 @@ void ASFormatter::findReturnTypeSplitPoint(const std::string& firstLine)             }             if (line[i] == '{')             {-                if (shouldBreakReturnType && foundSplitPoint && !isAlreadyBroken)+                if (shouldBreakReturnType && foundSplitPoint && !isAlreadyBroken && hasReturnType)                 {                     methodBreakCharNum = breakCharNum;                     methodBreakLineNum = breakLineNum;@@ -7716,7 +7907,7 @@ void ASFormatter::findReturnTypeSplitPoint(const std::string& firstLine)             }             if (line[i] == ';')             {-                if (shouldBreakReturnTypeDecl && foundSplitPoint && !isAlreadyBroken)+                if (shouldBreakReturnTypeDecl && foundSplitPoint && !isAlreadyBroken && hasReturnType)                 {                     methodBreakCharNum = breakCharNum;                     methodBreakLineNum = breakLineNum;