From 7a5dd90cff3625916a136c5acce76888fee9994b Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Thu, 6 Feb 2020 16:47:37 -0800 Subject: [PATCH] Added fixit for adding enum cases --- IDE/src/IDEApp.bf | 2 +- IDE/src/Project.bf | 1 - IDE/src/ui/AutoComplete.bf | 12 +- IDE/src/ui/SourceEditWidgetContent.bf | 34 +--- IDEHelper/Compiler/BfAutoComplete.cpp | 207 +++++++++++++++++++++++++ IDEHelper/Compiler/BfAutoComplete.h | 5 +- IDEHelper/Compiler/BfExprEvaluator.cpp | 133 +++------------- 7 files changed, 247 insertions(+), 147 deletions(-) diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index e08ae004..472f44e5 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -3651,7 +3651,7 @@ namespace IDE [IDECommand] public void Cmd_ReformatDocument() { - var sourceViewPanel = GetActiveSourceViewPanel(); + var sourceViewPanel = GetActiveSourceViewPanel(true); if (sourceViewPanel != null) sourceViewPanel.ReformatDocument(); } diff --git a/IDE/src/Project.bf b/IDE/src/Project.bf index 467331f8..5ab39527 100644 --- a/IDE/src/Project.bf +++ b/IDE/src/Project.bf @@ -1325,7 +1325,6 @@ namespace IDE public ~this() { - NOP!(); } public void GetProjectRelPath(String fullPath, String outRelPath) diff --git a/IDE/src/ui/AutoComplete.bf b/IDE/src/ui/AutoComplete.bf index 3bbec245..a41d7d59 100644 --- a/IDE/src/ui/AutoComplete.bf +++ b/IDE/src/ui/AutoComplete.bf @@ -237,11 +237,6 @@ namespace IDE.ui //Debug.WriteLine("Init {} {} {} {}", this, mIsInitted, mOwnsWindow, mAutoComplete); - if (WidgetWindow.sOnMouseDown.Count > 0) - { - NOP!(); - } - if (mOwnsWindow) { WidgetWindow.sOnWindowLostFocus.Add(new => LostFocusHandler); @@ -369,7 +364,6 @@ namespace IDE.ui public ~this() { - } public void Draw(Graphics g) @@ -2187,6 +2181,12 @@ namespace IDE.ui SourceViewPanel sourceViewPanel = IDEApp.sApp.ShowSourceFile(fixitFileName); if (sourceViewPanel != null) { + if (sourceViewPanel.IsReadOnly) + { + gApp.Fail(scope String()..AppendF("The selected fixit cannot be applied to locked file '{}'", sourceViewPanel.mFilePath)); + return; + } + var targetSourceEditWidgetContent = mTargetEditWidget.Content as SourceEditWidgetContent; var history = targetSourceEditWidgetContent.RecordHistoryLocation(); history.mNoMerge = true; diff --git a/IDE/src/ui/SourceEditWidgetContent.bf b/IDE/src/ui/SourceEditWidgetContent.bf index 7248ff11..4655a905 100644 --- a/IDE/src/ui/SourceEditWidgetContent.bf +++ b/IDE/src/ui/SourceEditWidgetContent.bf @@ -1326,15 +1326,6 @@ namespace IDE.ui int alignColumn = GetLineEndColumn(lineAndColumn.mLine, isBlock, true, true); - if ((useString.StartsWith("case ")) || - (useString.StartsWith("when ")) || - (useString.StartsWith("default:")) || - (useString.StartsWith("default "))) - { - //CursorLineAndColumn = LineAndColumn(lineAndColumn.mLine, alignColumn - tabSpaceCount); - //alignColumn--; - } - String linePrefix = scope String('\t', alignColumn / tabSpaceCount); CursorLineAndColumn = LineAndColumn(lineAndColumn.mLine, alignColumn); @@ -1342,10 +1333,11 @@ namespace IDE.ui if (useString.StartsWith("{")) isFullSwitch = true; - if ((useString.StartsWith("case ")) || - (useString.StartsWith("when ")) || - (useString.StartsWith("default:")) || - (useString.StartsWith("default "))) + if ((useString.Contains(':')) && + ((useString.StartsWith("case ")) || + (useString.StartsWith("when ")) || + (useString.StartsWith("default:")) || + (useString.StartsWith("default ")))) { CursorLineAndColumn = LineAndColumn(lineAndColumn.mLine, Math.Max(0, alignColumn - tabSpaceCount)); @@ -2110,6 +2102,7 @@ namespace IDE.ui bool hasEmptyAutocompleteReplace = true; if (mAutoComplete != null) hasEmptyAutocompleteReplace = mAutoComplete.mInsertEndIdx == -1; + bool didAutoComplete = false; bool isEndingChar = (keyChar >= (char8)32) && !keyChar.IsLetterOrDigit && (keyChar != '_') && (keyChar != '~') && (keyChar != '=') && (keyChar != '!') && (keyChar != ':'); @@ -2203,6 +2196,7 @@ namespace IDE.ui { if (IsCursorVisible(false)) mOnGenerateAutocomplete('\0', default); + didAutoComplete = true; } else { @@ -2602,25 +2596,13 @@ namespace IDE.ui if (mAutoComplete != null) { mAutoComplete.UpdateAsyncInfo(); - - /*if (mAutoComplete != null) - { - String filter = scope String(); - mAutoComplete.GetFilter(filter); - if ((filter.Length < mAutoComplete.mInfoFilter.Length) || (mAutoComplete.mInfoFilter.Length == 1)) - { - needsFreshAutoComplete = true; - } - }*/ needsFreshAutoComplete = true; } - if (needsFreshAutoComplete) + if ((needsFreshAutoComplete) && (!didAutoComplete)) { - //Profiler.StartSampling(); if (IsCursorVisible(false)) mOnGenerateAutocomplete(keyChar, isHighPri ? .HighPriority : default); - //Profiler.StopSampling(); } } else if (mData.mCurTextVersionId != startRevision) diff --git a/IDEHelper/Compiler/BfAutoComplete.cpp b/IDEHelper/Compiler/BfAutoComplete.cpp index 865b259a..bd7e0779 100644 --- a/IDEHelper/Compiler/BfAutoComplete.cpp +++ b/IDEHelper/Compiler/BfAutoComplete.cpp @@ -2645,4 +2645,211 @@ void BfAutoComplete::FixitAddMember(BfTypeInstance* typeInst, BfType* fieldType, } AddEntry(AutoCompleteEntry("fixit", StrFormat("Create field '%s' in '%s'\taddField|%s|%d||%s", fieldName.c_str(), fullName.c_str(), parser->mFileName.c_str(), fileLoc, fieldStr.c_str()).c_str())); +} + +void BfAutoComplete::FixitAddCase(BfTypeInstance* typeInst, const StringImpl& caseName, const BfTypeVector& fieldTypes) +{ + if (typeInst == mModule->mContext->mBfObjectType) + return; + + auto parser = typeInst->mTypeDef->mSource->ToParser(); + if (parser == NULL) + return; + + String fullName = typeInst->mTypeDef->mFullName.ToString(); + String fieldStr; + + int fileLoc = typeInst->mTypeDef->mTypeDeclaration->GetSrcEnd(); + + if (auto defineBlock = BfNodeDynCast(typeInst->mTypeDef->mTypeDeclaration->mDefineNode)) + fileLoc = BfFixitFinder::FindLineStartAfter(defineBlock->mOpenBrace); + if (!typeInst->mTypeDef->mFields.empty()) + { + auto fieldDecl = typeInst->mTypeDef->mFields.back()->mFieldDeclaration; + if (fieldDecl != NULL) + { + fileLoc = BfFixitFinder::FindLineStartAfter(fieldDecl); + } + } + + bool isSimpleCase = false; + if (!typeInst->mTypeDef->mFields.IsEmpty()) + { + if (auto block = BfNodeDynCast(typeInst->mTypeDef->mTypeDeclaration->mDefineNode)) + { + bool endsInComma = false; + + if (!block->mChildArr.IsEmpty()) + { + auto lastNode = block->mChildArr.back(); + if (auto tokenNode = BfNodeDynCast(lastNode)) + { + if (tokenNode->mToken == BfToken_Comma) + { + isSimpleCase = true; + endsInComma = true; + } + } + else if (auto enumEntryDecl = BfNodeDynCast(lastNode)) + { + isSimpleCase = true; + } + } + + if (isSimpleCase) + { + if (endsInComma) + { + fieldStr += "|"; + fieldStr += caseName; + } + else + { + auto fieldDef = typeInst->mTypeDef->mFields.back(); + fileLoc = fieldDef->mFieldDeclaration->GetSrcEnd(); + fieldStr += ",\r"; + fieldStr += caseName; + } + } + } + } + + if (!isSimpleCase) + { + fieldStr += "|case "; + fieldStr += caseName; + + if (!fieldTypes.IsEmpty()) + { + fieldStr += "("; + FixitGetParamString(fieldTypes, fieldStr); + fieldStr += ")"; + } + fieldStr += ";"; + } + + AddEntry(AutoCompleteEntry("fixit", StrFormat("Create case '%s' in '%s'\taddField|%s|%d|%s", caseName.c_str(), fullName.c_str(), parser->mFileName.c_str(), fileLoc, fieldStr.c_str()).c_str())); +} + +void BfAutoComplete::FixitGetParamString(const BfTypeVector& paramTypes, StringImpl& outStr) +{ + std::set usedNames; + + for (int argIdx = 0; argIdx < (int)paramTypes.size(); argIdx++) + { + if (argIdx > 0) + outStr += ", "; + BfType* paramType = paramTypes[argIdx]; + String checkName = "param"; + if (paramType != NULL) + { + bool isOut = false; + bool isArr = false; + + BfType* checkType = paramType; + while (true) + { + if ((checkType->IsArray()) || (checkType->IsSizedArray())) + { + isArr = true; + checkType = checkType->GetUnderlyingType(); + } + else if (checkType->IsRef()) + { + BfRefType* refType = (BfRefType*)checkType; + if (refType->mRefKind == BfRefType::RefKind_Out) + isOut = true; + checkType = refType->GetUnderlyingType(); + } + else if (checkType->IsTypeInstance()) + { + BfTypeInstance* typeInst = (BfTypeInstance*)checkType; + checkName = typeInst->mTypeDef->mName->ToString(); + if (checkName == "String") + checkName = "Str"; + if (checkName == "Object") + checkName = "Obj"; + if (isOut) + checkName = "out" + checkName; + else if (isupper(checkName[0])) + checkName[0] = tolower(checkName[0]); + if (isArr) + checkName += "Arr"; + break; + } + else + break; + } + + outStr += mModule->TypeToString(paramType, BfTypeNameFlag_ReduceName); + } + else + { + checkName = "param"; + outStr += "Object"; + } + + for (int i = 1; i < 10; i++) + { + String lookupName = checkName; + if (i > 1) + lookupName += StrFormat("%d", i); + if (usedNames.insert(lookupName).second) + { + outStr += " " + lookupName; + break; + } + } + } +} + +void BfAutoComplete::FixitAddMethod(BfTypeInstance* typeInst, const StringImpl& methodName, BfType* returnType, const BfTypeVector& paramTypes, bool wantStatic) +{ + if ((typeInst->IsEnum()) && (returnType == typeInst) && (wantStatic)) + { + FixitAddCase(typeInst, methodName, paramTypes); + return; + } + + if ((typeInst->mTypeDef->mSource != NULL) && (typeInst != mModule->mContext->mBfObjectType)) + { + auto parser = typeInst->mTypeDef->mSource->ToParser(); + if (parser != NULL) + { + String fullName = typeInst->mTypeDef->mFullName.ToString(); + String methodStr; + + if (typeInst == mModule->mCurTypeInstance) + { + // Implicitly private + } + else if (mModule->TypeIsSubTypeOf(mModule->mCurTypeInstance, typeInst)) + { + methodStr += "protected "; + } + else + { + methodStr += "public "; + } + + if (wantStatic) + methodStr += "static "; + + if (returnType != NULL) + methodStr += mModule->TypeToString(returnType, BfTypeNameFlag_ReduceName); + else + methodStr += "void"; + + methodStr += " " + methodName + "("; + + FixitGetParamString(paramTypes, methodStr); + + int fileLoc = typeInst->mTypeDef->mTypeDeclaration->GetSrcEnd(); + if (auto defineBlock = BfNodeDynCast(typeInst->mTypeDef->mTypeDeclaration->mDefineNode)) + fileLoc = defineBlock->mCloseBrace->GetSrcStart(); + + methodStr += ")"; + AddEntry(AutoCompleteEntry("fixit", StrFormat("Create method '%s' in '%s'\taddMethod|%s|%d|||%s|{||}", methodName.c_str(), fullName.c_str(), parser->mFileName.c_str(), fileLoc, methodStr.c_str()).c_str())); + } + } } \ No newline at end of file diff --git a/IDEHelper/Compiler/BfAutoComplete.h b/IDEHelper/Compiler/BfAutoComplete.h index 19111214..d720719d 100644 --- a/IDEHelper/Compiler/BfAutoComplete.h +++ b/IDEHelper/Compiler/BfAutoComplete.h @@ -219,6 +219,7 @@ public: void AddTypeInstanceEntry(BfTypeInstance* typeInst); void CheckDocumentation(AutoCompleteEntry* entry, BfCommentNode* documentation); bool GetMethodInfo(BfMethodInstance* methodInst, StringImpl* methodName, StringImpl* insertString, bool isExplicitInterface); + void FixitGetParamString(const BfTypeVector& paramTypes, StringImpl& outStr); public: BfAutoComplete(BfResolveType resolveType = BfResolveType_Autocomplete); @@ -248,7 +249,9 @@ public: bool CheckFixit(BfAstNode* node); void ChcekInterfaceFixit(BfTypeInstance* typeInstance, BfAstNode* node); - void FixitAddMember(BfTypeInstance* typeInst, BfType* fieldType, const StringImpl& fieldName, bool isStatic, BfTypeInstance* referencedFrom); + void FixitAddMember(BfTypeInstance* typeInst, BfType* fieldType, const StringImpl& fieldName, bool isStatic, BfTypeInstance* referencedFrom); + void FixitAddCase(BfTypeInstance * typeInst, const StringImpl & caseName, const BfTypeVector & fieldTypes); + void FixitAddMethod(BfTypeInstance* typeInst, const StringImpl& methodName, BfType* returnType, const BfTypeVector& paramTypes, bool wantStatic); }; diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 1b8fc9d1..68e07c63 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -4802,7 +4802,7 @@ void BfExprEvaluator::FinishDeferredEvals(SizedArrayImpl& argValu { for (int argIdx = 0; argIdx < argValues.size(); argIdx++) { - auto argValue = argValues[argIdx].mTypedValue; + auto& argValue = argValues[argIdx].mTypedValue; if ((argValues[argIdx].mArgFlags & (BfArgFlag_DelegateBindAttempt | BfArgFlag_LambdaBindAttempt | BfArgFlag_UnqualifiedDotAttempt | BfArgFlag_DeferredEval)) != 0) { if (!argValue) @@ -6661,129 +6661,31 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp if (methodDef == NULL) { + FinishDeferredEvals(argValues.mResolvedArgs); auto compiler = mModule->mCompiler; if ((compiler->IsAutocomplete()) && (compiler->mResolvePassData->mAutoComplete->CheckFixit(targetSrc))) { - mModule->CheckTypeRefFixit(targetSrc); - + mModule->CheckTypeRefFixit(targetSrc); bool wantStatic = !target.mValue; if ((targetType == NULL) && (allowImplicitThis)) { targetType = mModule->mCurTypeInstance; if (mModule->mCurMethodInstance != NULL) wantStatic = mModule->mCurMethodInstance->mMethodDef->mIsStatic; - } + } + if (targetType != NULL) { auto typeInst = targetType->ToTypeInstance(); - if ((typeInst->mTypeDef->mSource != NULL) && (typeInst != mModule->mContext->mBfObjectType)) - { - auto parser = typeInst->mTypeDef->mSource->ToParser(); - if (parser != NULL) - { - String fullName = typeInst->mTypeDef->mFullName.ToString(); - String methodStr; - if (typeInst == mModule->mCurTypeInstance) - { - // Implicitly private - } - else if (mModule->TypeIsSubTypeOf(mModule->mCurTypeInstance, typeInst)) - { - methodStr += "protected "; - } - else - { - methodStr += "public "; - } - - if (wantStatic) - methodStr += "static "; - - if (mExpectingType != NULL) - methodStr += mModule->TypeToString(mExpectingType, BfTypeNameFlag_ReduceName); - else - methodStr += "void"; - - methodStr += " " + methodName + "("; - - std::set usedNames; - - for (int argIdx = 0; argIdx < (int)argValues.mResolvedArgs.size(); argIdx++) - { - if (argIdx > 0) - methodStr += ", "; - auto& resolvedArg = argValues.mResolvedArgs[argIdx]; - String checkName = "param"; - if (resolvedArg.mTypedValue.mType != NULL) - { - bool isOut = false; - bool isArr = false; - - BfType* checkType = resolvedArg.mTypedValue.mType; - while (true) - { - if ((checkType->IsArray()) || (checkType->IsSizedArray())) - { - isArr = true; - checkType = checkType->GetUnderlyingType(); - } - else if (checkType->IsRef()) - { - BfRefType* refType = (BfRefType*)checkType; - if (refType->mRefKind == BfRefType::RefKind_Out) - isOut = true; - checkType = refType->GetUnderlyingType(); - } - else if (checkType->IsTypeInstance()) - { - BfTypeInstance* typeInst = (BfTypeInstance*)checkType; - checkName = typeInst->mTypeDef->mName->ToString(); - if (checkName == "String") - checkName = "Str"; - if (checkName == "Object") - checkName = "Obj"; - if (isOut) - checkName = "out" + checkName; - else if (isupper(checkName[0])) - checkName[0] = tolower(checkName[0]); - if (isArr) - checkName += "Arr"; - break; - } - else - break; - } - - methodStr += mModule->TypeToString(resolvedArg.mTypedValue.mType, BfTypeNameFlag_ReduceName); - } - else - { - checkName = "param"; - methodStr += "Object"; - } - - for (int i = 1; i < 10; i++) - { - String lookupName = checkName; - if (i > 1) - lookupName += StrFormat("%d", i); - if (usedNames.insert(lookupName).second) - { - methodStr += " " + lookupName; - break; - } - } - } - - int fileLoc = typeInst->mTypeDef->mTypeDeclaration->GetSrcEnd(); - if (auto defineBlock = BfNodeDynCast(typeInst->mTypeDef->mTypeDeclaration->mDefineNode)) - fileLoc = defineBlock->mCloseBrace->GetSrcStart(); - - methodStr += ")"; - compiler->mResolvePassData->mAutoComplete->AddEntry(AutoCompleteEntry("fixit", StrFormat("Create method '%s' in '%s'\taddMethod|%s|%d|||%s|{||}", methodName.c_str(), fullName.c_str(), parser->mFileName.c_str(), fileLoc, methodStr.c_str()).c_str())); - } + BfTypeVector paramTypes; + for (int argIdx = 0; argIdx < (int)argValues.mResolvedArgs.size(); argIdx++) + { + auto& resolvedArg = argValues.mResolvedArgs[argIdx]; + paramTypes.Add(resolvedArg.mTypedValue.mType); } + + autoComplete->FixitAddMethod(typeInst, methodName, mExpectingType, paramTypes, wantStatic); } } @@ -6794,8 +6696,7 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp else if (target.mType != NULL) mModule->Fail(StrFormat("Method '%s' does not exist in type '%s'", methodName.c_str(), mModule->TypeToString(target.mType).c_str()), targetSrc); else - mModule->Fail(StrFormat("Method '%s' does not exist", methodName.c_str()), targetSrc); - FinishDeferredEvals(argValues.mResolvedArgs); + mModule->Fail(StrFormat("Method '%s' does not exist", methodName.c_str()), targetSrc); return BfTypedValue(); } @@ -15902,6 +15803,14 @@ void BfExprEvaluator::DoMemberReference(BfMemberReferenceExpression* memberRefEx } } + if ((memberRefExpr->mTarget == NULL) && (expectingTypeInst != NULL) && (autoComplete != NULL)) + { + if (autoComplete->CheckFixit(memberRefExpr->mMemberName)) + { + autoComplete->FixitAddCase(expectingTypeInst, memberRefExpr->mMemberName->ToString(), BfTypeVector()); + } + } + if (mResult.mType == NULL) mModule->Fail("Unable to find member", nameRefNode); }