1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-18 16:10:26 +02:00

Added fixit for adding enum cases

This commit is contained in:
Brian Fiete 2020-02-06 16:47:37 -08:00
parent 75afbd4a3e
commit 7a5dd90cff
7 changed files with 247 additions and 147 deletions

View file

@ -3651,7 +3651,7 @@ namespace IDE
[IDECommand] [IDECommand]
public void Cmd_ReformatDocument() public void Cmd_ReformatDocument()
{ {
var sourceViewPanel = GetActiveSourceViewPanel(); var sourceViewPanel = GetActiveSourceViewPanel(true);
if (sourceViewPanel != null) if (sourceViewPanel != null)
sourceViewPanel.ReformatDocument(); sourceViewPanel.ReformatDocument();
} }

View file

@ -1325,7 +1325,6 @@ namespace IDE
public ~this() public ~this()
{ {
NOP!();
} }
public void GetProjectRelPath(String fullPath, String outRelPath) public void GetProjectRelPath(String fullPath, String outRelPath)

View file

@ -237,11 +237,6 @@ namespace IDE.ui
//Debug.WriteLine("Init {} {} {} {}", this, mIsInitted, mOwnsWindow, mAutoComplete); //Debug.WriteLine("Init {} {} {} {}", this, mIsInitted, mOwnsWindow, mAutoComplete);
if (WidgetWindow.sOnMouseDown.Count > 0)
{
NOP!();
}
if (mOwnsWindow) if (mOwnsWindow)
{ {
WidgetWindow.sOnWindowLostFocus.Add(new => LostFocusHandler); WidgetWindow.sOnWindowLostFocus.Add(new => LostFocusHandler);
@ -369,7 +364,6 @@ namespace IDE.ui
public ~this() public ~this()
{ {
} }
public void Draw(Graphics g) public void Draw(Graphics g)
@ -2187,6 +2181,12 @@ namespace IDE.ui
SourceViewPanel sourceViewPanel = IDEApp.sApp.ShowSourceFile(fixitFileName); SourceViewPanel sourceViewPanel = IDEApp.sApp.ShowSourceFile(fixitFileName);
if (sourceViewPanel != null) 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 targetSourceEditWidgetContent = mTargetEditWidget.Content as SourceEditWidgetContent;
var history = targetSourceEditWidgetContent.RecordHistoryLocation(); var history = targetSourceEditWidgetContent.RecordHistoryLocation();
history.mNoMerge = true; history.mNoMerge = true;

View file

@ -1326,15 +1326,6 @@ namespace IDE.ui
int alignColumn = GetLineEndColumn(lineAndColumn.mLine, isBlock, true, true); 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); String linePrefix = scope String('\t', alignColumn / tabSpaceCount);
CursorLineAndColumn = LineAndColumn(lineAndColumn.mLine, alignColumn); CursorLineAndColumn = LineAndColumn(lineAndColumn.mLine, alignColumn);
@ -1342,10 +1333,11 @@ namespace IDE.ui
if (useString.StartsWith("{")) if (useString.StartsWith("{"))
isFullSwitch = true; isFullSwitch = true;
if ((useString.StartsWith("case ")) || if ((useString.Contains(':')) &&
((useString.StartsWith("case ")) ||
(useString.StartsWith("when ")) || (useString.StartsWith("when ")) ||
(useString.StartsWith("default:")) || (useString.StartsWith("default:")) ||
(useString.StartsWith("default "))) (useString.StartsWith("default "))))
{ {
CursorLineAndColumn = LineAndColumn(lineAndColumn.mLine, Math.Max(0, alignColumn - tabSpaceCount)); CursorLineAndColumn = LineAndColumn(lineAndColumn.mLine, Math.Max(0, alignColumn - tabSpaceCount));
@ -2110,6 +2102,7 @@ namespace IDE.ui
bool hasEmptyAutocompleteReplace = true; bool hasEmptyAutocompleteReplace = true;
if (mAutoComplete != null) if (mAutoComplete != null)
hasEmptyAutocompleteReplace = mAutoComplete.mInsertEndIdx == -1; hasEmptyAutocompleteReplace = mAutoComplete.mInsertEndIdx == -1;
bool didAutoComplete = false;
bool isEndingChar = (keyChar >= (char8)32) && !keyChar.IsLetterOrDigit && (keyChar != '_') && (keyChar != '~') && (keyChar != '=') && (keyChar != '!') && (keyChar != ':'); bool isEndingChar = (keyChar >= (char8)32) && !keyChar.IsLetterOrDigit && (keyChar != '_') && (keyChar != '~') && (keyChar != '=') && (keyChar != '!') && (keyChar != ':');
@ -2203,6 +2196,7 @@ namespace IDE.ui
{ {
if (IsCursorVisible(false)) if (IsCursorVisible(false))
mOnGenerateAutocomplete('\0', default); mOnGenerateAutocomplete('\0', default);
didAutoComplete = true;
} }
else else
{ {
@ -2602,25 +2596,13 @@ namespace IDE.ui
if (mAutoComplete != null) if (mAutoComplete != null)
{ {
mAutoComplete.UpdateAsyncInfo(); 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; needsFreshAutoComplete = true;
} }
if (needsFreshAutoComplete) if ((needsFreshAutoComplete) && (!didAutoComplete))
{ {
//Profiler.StartSampling();
if (IsCursorVisible(false)) if (IsCursorVisible(false))
mOnGenerateAutocomplete(keyChar, isHighPri ? .HighPriority : default); mOnGenerateAutocomplete(keyChar, isHighPri ? .HighPriority : default);
//Profiler.StopSampling();
} }
} }
else if (mData.mCurTextVersionId != startRevision) else if (mData.mCurTextVersionId != startRevision)

View file

@ -2646,3 +2646,210 @@ 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())); 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<BfBlock>(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<BfBlock>(typeInst->mTypeDef->mTypeDeclaration->mDefineNode))
{
bool endsInComma = false;
if (!block->mChildArr.IsEmpty())
{
auto lastNode = block->mChildArr.back();
if (auto tokenNode = BfNodeDynCast<BfTokenNode>(lastNode))
{
if (tokenNode->mToken == BfToken_Comma)
{
isSimpleCase = true;
endsInComma = true;
}
}
else if (auto enumEntryDecl = BfNodeDynCast<BfEnumEntryDeclaration>(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<String> 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<BfBlock>(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()));
}
}
}

View file

@ -219,6 +219,7 @@ public:
void AddTypeInstanceEntry(BfTypeInstance* typeInst); void AddTypeInstanceEntry(BfTypeInstance* typeInst);
void CheckDocumentation(AutoCompleteEntry* entry, BfCommentNode* documentation); void CheckDocumentation(AutoCompleteEntry* entry, BfCommentNode* documentation);
bool GetMethodInfo(BfMethodInstance* methodInst, StringImpl* methodName, StringImpl* insertString, bool isExplicitInterface); bool GetMethodInfo(BfMethodInstance* methodInst, StringImpl* methodName, StringImpl* insertString, bool isExplicitInterface);
void FixitGetParamString(const BfTypeVector& paramTypes, StringImpl& outStr);
public: public:
BfAutoComplete(BfResolveType resolveType = BfResolveType_Autocomplete); BfAutoComplete(BfResolveType resolveType = BfResolveType_Autocomplete);
@ -249,6 +250,8 @@ public:
void ChcekInterfaceFixit(BfTypeInstance* typeInstance, 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);
}; };

View file

@ -4802,7 +4802,7 @@ void BfExprEvaluator::FinishDeferredEvals(SizedArrayImpl<BfResolvedArg>& argValu
{ {
for (int argIdx = 0; argIdx < argValues.size(); argIdx++) 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 ((argValues[argIdx].mArgFlags & (BfArgFlag_DelegateBindAttempt | BfArgFlag_LambdaBindAttempt | BfArgFlag_UnqualifiedDotAttempt | BfArgFlag_DeferredEval)) != 0)
{ {
if (!argValue) if (!argValue)
@ -6661,11 +6661,11 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
if (methodDef == NULL) if (methodDef == NULL)
{ {
FinishDeferredEvals(argValues.mResolvedArgs);
auto compiler = mModule->mCompiler; auto compiler = mModule->mCompiler;
if ((compiler->IsAutocomplete()) && (compiler->mResolvePassData->mAutoComplete->CheckFixit(targetSrc))) if ((compiler->IsAutocomplete()) && (compiler->mResolvePassData->mAutoComplete->CheckFixit(targetSrc)))
{ {
mModule->CheckTypeRefFixit(targetSrc); mModule->CheckTypeRefFixit(targetSrc);
bool wantStatic = !target.mValue; bool wantStatic = !target.mValue;
if ((targetType == NULL) && (allowImplicitThis)) if ((targetType == NULL) && (allowImplicitThis))
{ {
@ -6673,117 +6673,19 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
if (mModule->mCurMethodInstance != NULL) if (mModule->mCurMethodInstance != NULL)
wantStatic = mModule->mCurMethodInstance->mMethodDef->mIsStatic; wantStatic = mModule->mCurMethodInstance->mMethodDef->mIsStatic;
} }
if (targetType != NULL) if (targetType != NULL)
{ {
auto typeInst = targetType->ToTypeInstance(); 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<String> usedNames;
BfTypeVector paramTypes;
for (int argIdx = 0; argIdx < (int)argValues.mResolvedArgs.size(); argIdx++) for (int argIdx = 0; argIdx < (int)argValues.mResolvedArgs.size(); argIdx++)
{ {
if (argIdx > 0)
methodStr += ", ";
auto& resolvedArg = argValues.mResolvedArgs[argIdx]; auto& resolvedArg = argValues.mResolvedArgs[argIdx];
String checkName = "param"; paramTypes.Add(resolvedArg.mTypedValue.mType);
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); autoComplete->FixitAddMethod(typeInst, methodName, mExpectingType, paramTypes, wantStatic);
}
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<BfBlock>(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()));
}
}
} }
} }
@ -6795,7 +6697,6 @@ BfTypedValue BfExprEvaluator::MatchMethod(BfAstNode* targetSrc, BfMethodBoundExp
mModule->Fail(StrFormat("Method '%s' does not exist in type '%s'", methodName.c_str(), mModule->TypeToString(target.mType).c_str()), targetSrc); mModule->Fail(StrFormat("Method '%s' does not exist in type '%s'", methodName.c_str(), mModule->TypeToString(target.mType).c_str()), targetSrc);
else else
mModule->Fail(StrFormat("Method '%s' does not exist", methodName.c_str()), targetSrc); mModule->Fail(StrFormat("Method '%s' does not exist", methodName.c_str()), targetSrc);
FinishDeferredEvals(argValues.mResolvedArgs);
return BfTypedValue(); 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) if (mResult.mType == NULL)
mModule->Fail("Unable to find member", nameRefNode); mModule->Fail("Unable to find member", nameRefNode);
} }