Skip to content

Commit ab58e90

Browse files
committed
745 Проверка не локализированной строки
1 parent ccf546d commit ab58e90

File tree

2 files changed

+355
-0
lines changed

2 files changed

+355
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/**
2+
*
3+
*/
4+
package com.e1c.v8codestyle.bsl.check;
5+
6+
import java.util.Collection;
7+
import java.util.Map;
8+
import java.util.Set;
9+
10+
import org.eclipse.xtext.util.Pair;
11+
import org.eclipse.xtext.util.Tuples;
12+
13+
import com._1c.g5.v8.dt.lcore.util.CaseInsensitiveString;
14+
import com._1c.g5.v8.dt.platform.IEObjectTypeNames;
15+
import com.google.inject.Singleton;
16+
17+
/**
18+
* @author Dmitriy Marmyshev
19+
*
20+
*/
21+
@Singleton
22+
public class LocalizableRegistry
23+
{
24+
25+
private Map<CaseInsensitiveString, Collection<Integer>> staticInvocation;
26+
27+
private Map<Pair<CaseInsensitiveString, Integer>, Collection<String>> dynamicInvocation;
28+
29+
private Map<CaseInsensitiveString, Collection<String>> dynamicProperties;
30+
31+
private volatile boolean initialized;
32+
33+
public Collection<Integer> getStaticInvocationParameters(String methodName)
34+
{
35+
if (methodName == null)
36+
{
37+
return Set.of();
38+
}
39+
checkInit();
40+
41+
return staticInvocation.getOrDefault(new CaseInsensitiveString(methodName), Set.of());
42+
}
43+
44+
public Collection<String> getDynamicTypesForMethod(String methodName, int index)
45+
{
46+
if (methodName == null || index < 0)
47+
{
48+
return Set.of();
49+
}
50+
51+
checkInit();
52+
53+
return dynamicInvocation.getOrDefault(Tuples.create(new CaseInsensitiveString(methodName), index), Set.of());
54+
}
55+
56+
public Collection<String> getDynamicTypesForProperty(String propertyName)
57+
{
58+
if (propertyName == null)
59+
{
60+
return Set.of();
61+
}
62+
63+
checkInit();
64+
65+
return dynamicProperties.getOrDefault(new CaseInsensitiveString(propertyName), Set.of());
66+
}
67+
68+
private void checkInit()
69+
{
70+
if (initialized)
71+
{
72+
return;
73+
}
74+
75+
init();
76+
}
77+
78+
private synchronized void init()
79+
{
80+
if (initialized)
81+
{
82+
return;
83+
}
84+
85+
initStaticInvocation();
86+
initDynamicInvocation();
87+
initDynamicProperties();
88+
89+
initialized = true;
90+
}
91+
92+
private void initStaticInvocation()
93+
{
94+
//@formatter:off
95+
96+
// Global context method name and index of localizable string parameter
97+
staticInvocation = Map.of(
98+
new CaseInsensitiveString("ПоказатьВопрос"), Set.of(1, 5), //$NON-NLS-1$
99+
new CaseInsensitiveString("ShowQueryBox"), Set.of(1, 5) //$NON-NLS-1$
100+
);
101+
//@formatter:on
102+
}
103+
104+
private void initDynamicInvocation()
105+
{
106+
//@formatter:off
107+
108+
// Object's method name and index of localizable string parameter, and collection of object's type names
109+
dynamicInvocation = Map.of(
110+
Tuples.create(new CaseInsensitiveString("Добавить"), 1), Set.of(IEObjectTypeNames.VALUE_LIST), //$NON-NLS-1$
111+
Tuples.create(new CaseInsensitiveString("Add"), 1), Set.of(IEObjectTypeNames.VALUE_LIST) //$NON-NLS-1$
112+
);
113+
114+
//@formatter:on
115+
116+
}
117+
118+
private void initDynamicProperties()
119+
{
120+
//@formatter:off
121+
122+
// Types that contains property Title
123+
Set<String> TITLE_TYPES = Set.of(
124+
IEObjectTypeNames.FORM_FIELD,
125+
IEObjectTypeNames.FORM_GROUP,
126+
IEObjectTypeNames.FORM_TABLE,
127+
IEObjectTypeNames.FORM_DECORATION,
128+
IEObjectTypeNames.FORM_COMMAND,
129+
"FormAttribute", //$NON-NLS-1$
130+
"FormItemAddition", //$NON-NLS-1$
131+
IEObjectTypeNames.FORM_BUTTON,
132+
IEObjectTypeNames.CLIENT_APPLICATION_FORM,
133+
"ConditionalAppearenceItem", //$NON-NLS-1$
134+
"AppearenceSettingItem", //$NON-NLS-1$
135+
"CollaborationSystemConversation", //$NON-NLS-1$
136+
"DeliverableNotification", //$NON-NLS-1$
137+
"RepresentableDocumentBatch", //$NON-NLS-1$
138+
"HTMLDocument", //$NON-NLS-1$
139+
"ValueTableColumn", //$NON-NLS-1$
140+
"ValueTreeColumn", //$NON-NLS-1$
141+
"DataCompositionAreaTemplateValueCollectionHeaderCell", //$NON-NLS-1$
142+
IEObjectTypeNames.DATA_COMPOSITION_USER_FIELD_EXPRESSION,
143+
IEObjectTypeNames.DATA_COMPOSITION_USER_FIELD_CASE,
144+
IEObjectTypeNames.DATA_COMPOSITION_SELECTED_FIELD_GROUP,
145+
IEObjectTypeNames.DATA_COMPOSITION_SELECTED_FIELD,
146+
IEObjectTypeNames.DATA_COMPOSITION_FILTER_AVAILABLE_FIELD,
147+
"NestedDataCompositionSchema", //$NON-NLS-1$
148+
"DataCompositionSchemaParameter", //$NON-NLS-1$
149+
"DataCompositionSchemaNestedDataSet", //$NON-NLS-1$
150+
"DataCompositionSchemaDataSetFieldFolder", //$NON-NLS-1$
151+
"DataCompositionSchemaDataSetField", //$NON-NLS-1$
152+
"DataCompositionSchemaCalculatedField", //$NON-NLS-1$
153+
IEObjectTypeNames.DATA_ANALYSIS_PARAMETERS,
154+
"GanttChartPlotArea", //$NON-NLS-1$
155+
"FileDialog" //$NON-NLS-1$
156+
);
157+
158+
// Types that contains property ToolTip
159+
// TODO add all types with tooltip
160+
Set<String> TOOL_TIP_TYPES = Set.of(
161+
IEObjectTypeNames.FORM_FIELD,
162+
IEObjectTypeNames.FORM_GROUP,
163+
IEObjectTypeNames.FORM_TABLE,
164+
IEObjectTypeNames.FORM_DECORATION,
165+
IEObjectTypeNames.FORM_COMMAND,
166+
"FormItemAddition", //$NON-NLS-1$
167+
"DateAppearence" //$NON-NLS-1$
168+
);
169+
170+
// TODO add types of graphical scheme with Description
171+
172+
// TODO add types of DCS with Presentation
173+
174+
// Localizable property name, and collection of types
175+
dynamicProperties = Map.of(
176+
new CaseInsensitiveString("Подсказка"), TOOL_TIP_TYPES, //$NON-NLS-1$
177+
new CaseInsensitiveString("ToolTip"), TOOL_TIP_TYPES, //$NON-NLS-1$
178+
new CaseInsensitiveString("ПодсказкаВвода"), Set.of("FormFieldExtenstionForTextBox"), //$NON-NLS-1$
179+
new CaseInsensitiveString("InputHint"), Set.of("FormFieldExtenstionForTextBox"), //$NON-NLS-1$
180+
new CaseInsensitiveString("Заголовок"), TITLE_TYPES, //$NON-NLS-1$
181+
new CaseInsensitiveString("Title"), TITLE_TYPES //$NON-NLS-1$
182+
);
183+
//@formatter:on
184+
185+
}
186+
187+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/*******************************************************************************
2+
* Copyright (C) 2022, 1C-Soft LLC and others.
3+
*
4+
* This program and the accompanying materials are made
5+
* available under the terms of the Eclipse Public License 2.0
6+
* which is available at https://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* 1C-Soft LLC - initial API and implementation
12+
*******************************************************************************/
13+
/**
14+
*
15+
*/
16+
package com.e1c.v8codestyle.bsl.check;
17+
18+
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.STRING_LITERAL;
19+
import static com._1c.g5.v8.dt.bsl.model.BslPackage.Literals.STRING_LITERAL__LINES;
20+
21+
import java.util.Collection;
22+
import java.util.List;
23+
import java.util.Objects;
24+
25+
import org.eclipse.core.runtime.IProgressMonitor;
26+
import org.eclipse.emf.ecore.EObject;
27+
import org.eclipse.xtext.EcoreUtil2;
28+
29+
import com._1c.g5.v8.dt.bsl.model.DynamicFeatureAccess;
30+
import com._1c.g5.v8.dt.bsl.model.FeatureAccess;
31+
import com._1c.g5.v8.dt.bsl.model.Invocation;
32+
import com._1c.g5.v8.dt.bsl.model.SimpleStatement;
33+
import com._1c.g5.v8.dt.bsl.model.StaticFeatureAccess;
34+
import com._1c.g5.v8.dt.bsl.model.StringLiteral;
35+
import com._1c.g5.v8.dt.bsl.resource.TypesComputer;
36+
import com._1c.g5.v8.dt.common.StringUtils;
37+
import com._1c.g5.v8.dt.mcore.Environmental;
38+
import com._1c.g5.v8.dt.mcore.TypeItem;
39+
import com._1c.g5.v8.dt.mcore.util.McoreUtil;
40+
import com.e1c.g5.v8.dt.check.CheckComplexity;
41+
import com.e1c.g5.v8.dt.check.ICheckParameters;
42+
import com.e1c.g5.v8.dt.check.components.BasicCheck;
43+
import com.e1c.g5.v8.dt.check.settings.IssueSeverity;
44+
import com.e1c.g5.v8.dt.check.settings.IssueType;
45+
import com.e1c.v8codestyle.check.CommonSenseCheckExtension;
46+
import com.e1c.v8codestyle.internal.bsl.BslPlugin;
47+
import com.google.inject.Inject;
48+
49+
/**
50+
* @author Dmitriy Marmyshev
51+
*
52+
*/
53+
public class NstrLocalizableStringCheck
54+
extends BasicCheck
55+
{
56+
private static final String CHECK_ID = "bsl-localizable-string"; //$NON-NLS-1$
57+
58+
private final TypesComputer typesComputer;
59+
60+
private final LocalizableRegistry localizableRegistry;
61+
62+
@Inject
63+
public NstrLocalizableStringCheck(TypesComputer typesComputer, LocalizableRegistry localizableRegistry)
64+
{
65+
this.typesComputer = typesComputer;
66+
this.localizableRegistry = localizableRegistry;
67+
}
68+
69+
@Override
70+
public String getCheckId()
71+
{
72+
return CHECK_ID;
73+
}
74+
75+
@Override
76+
protected void configureCheck(CheckConfigurer builder)
77+
{
78+
builder.title("String literal should be localizable with NStr")
79+
.description("String literal should be localizable with NStr")
80+
.complexity(CheckComplexity.NORMAL)
81+
.severity(IssueSeverity.MINOR)
82+
.issueType(IssueType.UI_STYLE)
83+
.extension(new CommonSenseCheckExtension(getCheckId(), BslPlugin.PLUGIN_ID))
84+
.module()
85+
.checkedObjectType(STRING_LITERAL);
86+
87+
}
88+
89+
@Override
90+
protected void check(Object object, ResultAcceptor resultAceptor, ICheckParameters parameters,
91+
IProgressMonitor monitor)
92+
{
93+
StringLiteral literal = (StringLiteral)object;
94+
95+
if (literal.getLines().size() == 1 && StringUtils.isBlank(literal.lines(true).get(0)))
96+
{
97+
// skip empty lines
98+
return;
99+
}
100+
101+
EObject parent = literal.eContainer();
102+
103+
if (parent instanceof Invocation && isLocalizableParameter((Invocation)parent, literal, monitor)
104+
|| parent instanceof SimpleStatement && ((SimpleStatement)parent).getLeft() instanceof DynamicFeatureAccess
105+
&& !monitor.isCanceled()
106+
&& isLocalizableProperty((DynamicFeatureAccess)((SimpleStatement)parent).getLeft(), monitor))
107+
{
108+
resultAceptor.addIssue("Localizable string should be in NStr()", STRING_LITERAL__LINES);
109+
}
110+
111+
}
112+
113+
private boolean isLocalizableParameter(Invocation inv, EObject parameter, IProgressMonitor monitor)
114+
{
115+
FeatureAccess method = inv.getMethodAccess();
116+
if (StringUtils.isBlank(method.getName()))
117+
{
118+
return false;
119+
}
120+
121+
if (method instanceof StaticFeatureAccess && !monitor.isCanceled())
122+
{
123+
Collection<Integer> params = localizableRegistry.getStaticInvocationParameters(method.getName());
124+
if (!params.isEmpty())
125+
{
126+
int index = inv.getParams().indexOf(parameter);
127+
return params.contains(index);
128+
}
129+
}
130+
else if (method instanceof DynamicFeatureAccess && !monitor.isCanceled())
131+
{
132+
int index = inv.getParams().indexOf(parameter);
133+
DynamicFeatureAccess dfa = (DynamicFeatureAccess)method;
134+
Collection<String> typeNames = localizableRegistry.getDynamicTypesForMethod(dfa.getName(), index);
135+
if (!typeNames.isEmpty() && !monitor.isCanceled())
136+
{
137+
Environmental env = EcoreUtil2.getContainerOfType(dfa, Environmental.class);
138+
List<TypeItem> types = typesComputer.computeTypes(dfa.getSource(), env.environments());
139+
return !types.isEmpty() && types.stream()
140+
.map(McoreUtil::getTypeName)
141+
.filter(Objects::nonNull)
142+
.anyMatch(typeNames::contains);
143+
}
144+
}
145+
return false;
146+
}
147+
148+
private boolean isLocalizableProperty(DynamicFeatureAccess property, IProgressMonitor monitor)
149+
{
150+
String name = property.getName();
151+
if (StringUtils.isBlank(name))
152+
{
153+
return false;
154+
}
155+
Collection<String> typeNames = localizableRegistry.getDynamicTypesForProperty(name);
156+
157+
if (!typeNames.isEmpty() && !monitor.isCanceled())
158+
{
159+
Environmental env = EcoreUtil2.getContainerOfType(property, Environmental.class);
160+
List<TypeItem> types = typesComputer.computeTypes(property.getSource(), env.environments());
161+
return !types.isEmpty()
162+
&& types.stream().map(McoreUtil::getTypeName).filter(Objects::nonNull).anyMatch(typeNames::contains);
163+
}
164+
165+
return false;
166+
}
167+
168+
}

0 commit comments

Comments
 (0)